什么是树
客观世界中,许多事物存在层次关系,例如:
家谱、社会组织结构、图书信息管理(某一个系列类下面有很多书)
分层次组织在管理上具有更高的效率
数据管理的基本操作有:插入、删除、查找
接下来,我们来研究下:如何实现有效率的查找?
查找
上面这个是没有哨兵的方法,需要在循环的时候,每次都要判断i>0是否成立
顺序查找算法的时间复杂度是O(n)
树
树的定义
树的一些基本术语
左上角的树,可以用链表形式得到右下角的链表形式
但是,每个节点的指针域不同,有的有3个指针域,有的有一个指针域,我们事先不知道每一个结点的指针域,这样,对我们的程序设计会有很大难度。
因此,我们可以把右下角的链表形式都设计为具有三个指针域的结构,比如B有三个指针域,第三个指针域为空。但是,这样做的话,n个结点,会有3n个指针域。实际上我们只需要n-1条边,也就是n-1个指针域为非零。这样会有(3n - (n - 1)) = 2n + 1个指针域是没用的,造成了空间上的浪费。
二叉树
二叉树有左右之分
度为2的树,没用左右之分
二叉树的几个重要性质
二叉树的存储结构
二叉树的遍历
中序和后序遍历,只是打印位置不一样而已,其余都一样。
这都是使用递归的方法实现的遍历,也可以使用非递归的方法实现:
使用栈
遇到一个节点入栈,中序遍历B入栈,中序遍历D入栈,D没有左子树,则D出栈,D没有右子树,然后B出栈。中序遍历F入栈,E入栈,E出栈,F出栈,A出栈。。。
二叉树遍历的核心问题其实是,如何将二维结构使其线性化
前中后序遍历都属于栈
而
层序遍历属于队列
不得不说,这老师讲的是真的好。
几个面试题例子
在原来先序遍历的基础上,添加判断条件,如果左右子树都为空,就是叶子结点
先序遍历、中序遍历、后序遍历都可以修改后用于判断叶子结点的个数
该算法思想是,想求出二叉树的高度,求出该二叉树的左子树的高度,二叉树的右子树高度,然后比较大小,让大的+1(根),就是二叉树的高度。
因为需要提前求出二叉树的左右子树高度,所以该算法是在后序遍历的基础上进行修改求得的。
所有的叶子结点都是运算数,所有的非叶子结点都是运算符
三种遍历,中序是不准确的,例如:d和e的父节点换成+,和f的父节点+换成,表达式变为:d+ef,这样会先运算*
解决办法是,在每一个子树前面加(,在子树完成后加)
前序中序、中序后序可以确定一个二叉树,没有中序不可以确定二叉树
树的同构
静态链表:使用结构数组表示
基本存储是数组,左右儿子用类似链表的方法表示,也就是:物理上的存储是数组,思想是链表
可以看出,同一个二叉树,使用静态链表表示,会有不同的方式,也就是,结点存储位置不固定,可以随意存储,只要对应的关系存储对就可以。
这是静态链表的灵活性所在,同时,也就造成了根节点不知道在哪的问题,因此,我们需要找到根节点。
需要根节点也简单,在left、right里面找到没有出现的下标值,就是根节点。