文章目录
1.查找
1.1 静态查找
顺序查找
顺序查找算法的时间复杂度为O(n)
二分查找
要查找的元素是存在的
要查找的元素是不存在的
二分查找算法
2.树的定义
怎么判定 树与非树呢?
3.树的基本术语
4.树的表示
儿子-兄弟 表示法
旋转45度,就可以变成二叉树了
5.二叉树
二叉树的定义
怎么判断完美二叉树 和 完全二叉树呢?
一棵深度为k且有 2^k - 1 个结点的二叉树称为满二叉树(完美二叉树)
分析:上图中树的深度是4,结点个数是 2^4 - 1 = 15
那么,将编号为15, 14, …, 9的叶子结点从右到左依次拿掉或者拿掉部分,则是一棵完全二叉树,例如,将上图中的编号为15, 14, 13, 12, 11叶子结点都拿掉(从右到左的顺序)
下图就不是一棵完全二叉树
分析:如果将编号11(K)结点从编号6(E)的左儿子位置移动到编号5(E)的右儿子位置,则变成一棵完全二叉树。
二叉树的几个重要性质
思考题:
有一颗二叉树,其两个儿子的结点个数为15个,一个儿子的结点个数为32个,问该二叉树的叶结点个数是多少?
n2 = 15;n1 = 32;
n0 = n2 - 1 = 16
所以该二叉树的叶结点个数是16
该二叉树总共有 n0 + n1 + 2 * n2 = 0 + 32 + 30 = 62 条边
也可以用 n0 + n1 + n2 = 63 表示该二叉树的总结点树,总边数 = 总结点数 - 1 = 62
二叉树基本操作
思考题
1、如果一个完全二叉树最底下一层为第六层(根为第一层)且该层共有8个叶结点,那么该完全二叉树共有多少个结点?
解析:
完全二叉树,除最后一层可以不满外,其他各层都必须是满的
前五层的结点个数是:2^5 - 1 = 31
加上最后一层 8 个结点
总共是 31 + 8 = 39
2、若有一二叉树的总结点数为98,只有一个儿子的结点数为48,则该树的叶结点数是多少?
解析:这样的树是不存在的,二叉树的总结点树是n0 + n1 + n2 = 98,又因为n1 = 48,
所以n0 + n2 = 50,n0 = n2 - 1,代入得n2 = 51/2,故这样的树是不存在的
3、设深度为d(只有一个根结点时,d为1)的二叉树只有度为0和2的结点,则此类二叉树的结点数至少为2d-1?
解析:正确。考虑结点最少的情况:
![]()
可以看到,该树每一级都只有一个节点有两个子节点。深度为d,即除了第一级,其余每一级都有2个节点,故总共2d-1个节点。
二叉树的存储结构
顺序存储结构
链式存储
二叉树遍历
先序遍历
中序遍历
后序遍历
总结
二叉树的递归遍历
void InorderTraversal( BinTree BT ) //中序遍历
{
if( BT ) {
InorderTraversal( BT->Left );
/* 此处假设对BT结点的访问就是打印数据 */
printf("%d ", BT->Data); /* 假设数据为整型 */
InorderTraversal( BT->Right );
}
}
void PreorderTraversal( BinTree BT ) //前序遍历
{
if( BT ) {
printf("%d ", BT->Data );
PreorderTraversal( BT->Left );
PreorderTraversal( BT->Right );
}
}
void PostorderTraversal( BinTree BT ) //后序遍历
{
if( BT ) {
PostorderTraversal( BT->Left );
PostorderTraversal( BT->Right );
printf("%d ", BT->Data);
}
}
void LevelorderTraversal ( BinTree BT )
{
Queue Q;
BinTree T;
if ( !BT ) return; /* 若是空树则直接返回 */
Q = CreatQueue(); /* 创建空队列Q */
AddQ( Q, BT );
while ( !IsEmpty(Q) ) {
T = DeleteQ( Q );
printf("%d ", T->Data); /* 访问取出队列的结点 */
if ( T->Left ) AddQ( Q, T->Left );
if ( T->Right ) AddQ( Q, T->Right );
}
}
二叉树的非递归遍历
基本思路:使用堆栈
中序遍历非递归算法
先序遍历非递归算法
无图,直接上代码
void InOrderTraversal(BinTree BT) {
BinTree T = BT;
Stack S = CreateStack(MaxSize);
while (T || !IsEmpty(S)) { //如果二叉树存在,并且堆栈不为空
while (T) { //先打印该结点,并压入堆栈,再向左一直遍历
printf("%5d", T->Data);
Push(S, T);
T = T->Left;
}
if (!IsEmpty(S)) {
T = Pop(S); //将结点弹出堆栈
T = T->Right; //将该结点向右遍历
}
}
}
层序遍历
遍历二叉树的应用
由两种遍历序列确定二叉树
注意:必须要有中序遍历,才能确定二叉树
先由先序序列的第一个元素,确定根结点
再把根结点放到中序序列,确定左子树有哪些元素
![image-20210307165743484](https://i-blog.csdnimg.cn/blog_migrate/4b23aed2fedd191bb694962ec90f4533.png)
![image-20210307170656159](https://i-blog.csdnimg.cn/blog_migrate/d80d95958772f658e9396711edb4a655.png)
![image-20210307170624774](https://i-blog.csdnimg.cn/blog_migrate/05ad187d6b491c5f6e7cf87dfd1c3505.png)
思考题
1、假定只有四个结点A、B、C、D的二叉树,其前序遍历序列为ABCD,则下面哪个序列是不可能的中序遍历序列?
A、ABCD
B、ACDB
C、DCBA
D、DABC
解析:
选项A有可能:
选项B有可能:
选项C有可能:
选项D:首先根据中序,A在中间,所以左子树的节点只有一个D,而右子树节点是B和C,但问题是根据前序遍历的规则,打印出A以后应该接着打印B,但是若D在左子树,B在右子树,则前序遍历不可能先打印出B再打印出D,所以这种情况不可能。
2、对于二叉树,如果其中序遍历结果与前序遍历结果一样,那么可以断定该二叉树
解析:所有结点都没有左儿子
3、已知一二叉树的后序和中序遍历的结果分别是FDEBGCA 和FDBEACG,那么该二叉树的前序遍历结果是什么?
![]()