树的遍历
程序员文章站
2022-05-19 20:55:18
...
普通遍历
普通遍历的意思是时间复杂度为O(N),空间复杂度为O(h)的遍历算法,区别于后边学习的Morris遍历
递归遍历
树的定义本身就是递归的,所以非常适合用递归解决问题,树的遍历同样可以用递归来解决。递归的模型非常简单。先中后序的基本都是一样的。
先序遍历
func preOrder(root *node) {
if root == nil {
return
}
fmt.Println(root.value)
preOrder(root.left)
preOrder(root.right)
}
func PreOrderRecur(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("PreOrder")
preOrder(btree.root)
fmt.Println("----------------------------------")
return nil
}
中序遍历
func inOrder(root *node) {
if root == nil {
return
}
inOrder(root.left)
fmt.Println(root.value)
inOrder(root.right)
}
func InOrderRecur(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("InOrder")
inOrder(btree.root)
fmt.Println("----------------------------------")
return nil
}
后序遍历
func posOrder(root *node) {
if root == nil {
return
}
posOrder(root.left)
posOrder(root.right)
fmt.Println(root.value)
}
func PosOrderRecur(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("PostOrder")
posOrder(btree.root)
fmt.Println("----------------------------------")
return nil
}
递归总结
虽然递归的代码非常简单,但是它的本质一定要清楚。这个本质是听左神讲的,非常精辟。递归的本质是每个节点都会访问三次,而递归的先中后序的遍历无非是你把打印行为选择在哪一次。
层次遍历
层次遍历就是从上到下,从左到右的访问每一个节点。
func LevelTranversal(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("level tranversal")
if btree.root == nil {
return nil
}
queue := list.New()
queue.PushFront(btree.root)
var cur *node
for queue.Len() != 0 {
cur = queue.Back().Value.(*node)
queue.Remove(queue.Back())
fmt.Println(cur.value)
if cur.left != nil {
queue.PushFront(cur.left)
}
if cur.right != nil {
queue.PushFront(cur.right)
}
}
fmt.Println("----------------------------------")
return nil
}
就是广度优先遍历,采用一个队列,初始把根节点压入队列,每次从队列弹出一个元素打印,然后将左右两个子节点依次压入队列,重复直到队列为空
非递归遍历
虽然递归的实现先中后序的遍历非常简单直观,但是系统栈容量不是很大,当树中深度过深时,可能会导致系统栈爆掉,所以我们为了避免这个问题,就需要我们自己使用用户栈去实现非递归的遍历
先序遍历
非递归的先序遍历和层次遍历的实现基本一致,无非就是队列换成了栈,压入左右孩子的顺序相反
func PreOrder(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("PreOrder")
if btree.root == nil {
return nil
}
stack := list.New()
stack.PushFront(btree.root)
var cur *node
for stack.Len() != 0 {
cur = stack.Front().Value.(*node)
stack.Remove(stack.Front())
fmt.Println(cur.value)
if cur.right != nil {
stack.PushFront(cur.right)
}
if cur.left != nil {
stack.PushFront(cur.left)
}
}
fmt.Println("----------------------------------")
return nil
}
中序遍历
- 初始使用一个游标指向根节点
- 如果游标指向的不是空则压栈,并移动到左子树
- 如果左子树不为空则重复2,否则弹栈打印,并将游标指向弹出的节点的右子树
func InOrder(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("InOrder")
if btree.root == nil {
return nil
}
var top *node
cur := btree.root
stack := list.New()
for stack.Len() != 0 || cur != nil {
if cur != nil {
stack.PushFront(cur)
cur = cur.left
continue
}
top = stack.Front().Value.(*node)
stack.Remove(stack.Front())
fmt.Println(top.value)
cur = top.right
}
return nil
}
总结一下其实就是模仿了递归,第一次访问压栈,第二次打印,第三次压右孩子
后序遍历
非递归的后序遍历和层次遍历也很像,压入左右孩子的性顺序也相同,只不过使用的是栈,而且需要把从栈中弹出的元素都添加到打印栈中
func PosOrder(btree *btree) error {
if btree == nil {
return errors.New("the btree is not exist")
}
fmt.Println("----------------------------------")
fmt.Println("PosOrder")
if btree.root == nil {
return nil
}
stackRecur := list.New()
stackPrint := list.New()
stackRecur.PushFront(btree.root)
var cur *node
for stackRecur.Len() != 0 {
cur = stackRecur.Front().Value.(*node)
stackRecur.Remove(stackRecur.Front())
if cur.left != nil {
stackRecur.PushFront((cur.left))
}
if cur.right != nil {
stackRecur.PushFront(cur.right)
}
stackPrint.PushFront(cur)
}
for stackPrint.Len() != 0 {
cur = stackPrint.Front().Value.(*node)
stackPrint.Remove(stackPrint.Front())
fmt.Println(cur.value)
}
return nil
}