【无标题】二叉树的遍历

本文介绍了二叉树的基本性质,如在第i层最多有2^(i-1)个节点,深度为k的二叉树最多有2^k-1个节点。完全二叉树的概念被提出,并指出其在查找操作中的高效性,时间复杂度为O(logn)。同时,讲解了二叉树的前序、中序和后序遍历,以及如何用非递归方式实现中序遍历。通过模拟递归函数的函数栈,可以实现非递归遍历,简化程序设计。
摘要由CSDN通过智能技术生成

1. 在二叉树的第 i 层上至多有 [公式] 个结点

第一层有1个,第二层最多只可能是第1层的两倍,第三层是第二层的两倍。

2. 深度为 k 的二叉树,最多有 [公式] 个结点。

这条性质由 1 可以直接得出:将每一层的最大结点数相加。这是一个公比为 2 的等比数列,其和为 [公式]。

另一个定义,如果一个深度为 k 的二叉树,正好有 [公式] 个结点,那么这棵树就被称为满二叉树。如果一个二叉树,只有当第 k 层已经达到了 [公式] 的最大值以后,才能往第 k + 1 层自左向右地添加结点,这棵树就被称为完全二叉树。

3. 具有 n 个结点的完全二叉树的深度为 [公式]

这个性质就是性质二的直接推论。这个性质向我们揭示了一个问题:受二叉树的树形的影响,同样有n个结点的一个二叉树,它的高度可能差别很大。比如,我们上节课的作业第二题,如果二叉搜索树是以(1, 2, 3, 4, 5, 6)或者(6, 5, 4, 3, 2, 1)的顺序插入的话,二叉树的高度就是6,退化为链表。上节课的第一题,我们看到了,二叉树中的搜索效率与树的高度成正比。二叉树越矮,我们就能越快地找到目标,二叉树越高,要经过的结点就会越多。

当树形为完全二叉树时,在树中进行查找的时间复杂度是 O(log n),而当树形退化为链表时,查找的时间复杂度是 O(n),这个时间复杂度的差别是十分巨大的,大家可以算一下,如果有1000个结点,O(n)的时间复杂度,意味着1000次比较,而O(log n)的时间复杂度,只有10次比较,性能可以提升100倍。好的数据结构和算法设计的威力可见一斑。

另外,完全二叉树的定义是很重要的,因为我们后面会学习一种威力十分强大的数据结构:堆,它就是一个完全二叉树。所以请记住完全二叉树。

 

二叉树的遍历

并且使用递归实现了二叉树的前序遍历

这里,先介绍一下三种常用的遍历方式:

 

1. 前序遍历。先访问根结点,再前序遍历左子树,最后前序遍历右子树。可见,这个操作的定义就是递归的。

 

2. 中序遍历。先中序遍历左子树,再访问根结点,最后中序遍历右子树。由于左子树上的值都比根结点小,右子树上的值都比根结点大,所以,中序遍历一棵树所得到的结果,是从小到大有序的,可以根据这个特点,来检验你的中序遍历是否正确实现了。

 

3. 后序遍历。先后序遍历左子树,再后序遍历右子树,最后访问根结点。

 

定义非常简单,前,中,后,无非就是说的根结点在什么时机被访问而已。还有其他的遍历方式,但这三种是我们最常用的,希望大家彻底理解它。我这里再给出中序遍历的代码,大家自己完成后序的:

 

    public void midOrder(Node n) {

        if (n.left != null)

            midOrder(n.left);

        System.out.println(n.data);

        if (n.right != null)

            midOrder(n.right);

    }

非递归遍历二叉树

在很多笔试题中,二叉树的非递归遍历是一个很常见的考题。非递归遍历有很多种实现方式,掌握起来要耗费很大的精力,而且还容易忘记。这一节将会介绍一种模拟递归函数的函数栈,从而实现非递归遍历。

 

如果将未访问完的结点入栈,每次只对栈顶元素进行操作,一旦栈顶元素被全部处理完,就将其出栈。继续取栈顶元素进行处理,这就相当于回溯到了父结点。但是每次子结点全部访问完回溯到父结点时,都需要知道父结点已经执行到哪一步了,在递归程序中,这个值是放在子结点所对应栈的 old EIP 中的,因此,这是我们要模拟的一个值。由于不需要像真正的递归程序那样在回溯时恢复调用者的函数栈,所以 old EBP 和 old ESP 这两个值是,经过分析,我们可以给结点的定义加上一个变量state来模拟old EIP:

 

class Node<T> {

    public T data;

    public Node left;

    public Node right;

    public int state;

 

    public Node(T d) {

        this.data = d;

    }

}

为结点增加 state 变量,来标记当前结点已经访问到哪一步。每次从子结点回溯回来的时候,都可以直接从当前结点里取出,这样就可以更加简化这个程序。给出非递归的中序遍历的代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值