树的遍历

普通遍历

普通遍历的意思是时间复杂度为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
}

中序遍历

  1. 初始使用一个游标指向根节点
  2. 如果游标指向的不是空则压栈,并移动到左子树
  3. 如果左子树不为空则重复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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值