一、引子
1.静态查找
二分查找
时间复杂度会变小log(n)
条件:数组且有序
判定树
每个结点需要的查找次数刚好为该结点所在层数;
查找次数不会超过树的深度
树的深度表示为最坏情况下需要进行的查找次数为
深度
=
l
o
g
2
N
+
1
深度=log2N+1
深度=log2N+1
ASL(平均成功查找次数)->变小
启示
以查找树的形式直接存放数据在查找时达到时间复杂度和二分查找近似的效果
2.动态查找
二、树的定义
1.特性:
1).n个结点构成的有限的集合,n=0时代表空树。
2).有一个为“root”的特殊节点(r),其余结点互不相交其下又是个集合,是子树(递归)
3).子树不相交
4).除了根节点外每个结点有且仅有一个父节点
5).一个n结点的树仅有(n-1)条边
2.术语
1).结点的度:结点的子树个数
2).树的度:树的所有结点中最大的度数
3).叶结点:度为 ‘0’ 的结点 --没有子树的结点
4).父节点:
5).子结点:
6).兄弟结点:
7).路径和路径的长度:从结点n1到nk的路径为一个结点序列n1,n2,nk,ni是n(i+1)的父节点。路径所包含的边的个数为路径长度
8).祖先节点:
9).子孙节点:
10).结点的层次:根结点在第1层,其它结点的层数是其父结点的层数+1
11).树的深度:树中所有结点中的最大层次是这棵树的深度
三、树的表示
儿子兄弟表示方法
两个指针一个指向第一个儿子,另一个指向下一个兄弟(长兄如父) ->引入二叉树,结点的度为 '2’的树
四.二叉树
1.定义
一个有穷的结点集合,由根节点和称其左子树和右子树的两个不相交的二叉树组成
2.形态
空、只有根节点、左子树、右子树、左右都有
3.二叉树的顺序子树有左右之分
4.特殊二叉树
斜二叉树
完美二叉树(满二叉树):每个结点都有两个子树
完全二叉树:完美二叉树的最后一层允许缺项
5.性质
1)一个二叉树的第i层的最大结点数为2^(i-1),i>=1
2)深度为k的二叉树有最大结点总数为2^k-1,k>=1
3)对任何非空二叉树T,n0表示叶结点的个数、n2表示度为2的结点个数,则n0=n2+1
6.存储结构
1)顺序存储结构
数组存储一般存完全二叉树,存其他的会比较浪费
2)链表存储
7.遍历
先序遍历:根结点->左子树->右子树
void preot(bt a){
if(a){
printf("%d",a->data);
preot(a->left);
preot(a->right);
}
}
中序遍历:左子树->根结点->右子树
void preot(bt a){
if(a){
preot(a->left);
printf("%d",a->data);
preot(a->right);
}
}
后序遍历: 左子树->右子树->根结点
void preot(bt a){
if(a){
preot(a->left);
preot(a->right);
printf("%d",a->data);
}
}
三种方式路线一样但是访问结点的时机不同。
中序非递归遍历:使用堆栈
遇到一个结点,压栈,遍历左子树;
当左子树遍历结束后从栈顶弹出结点并访问;
然后按右指针再去中序遍历该右子树
void preot(bt a){
stack s=creatstack(maxsize);
while(a||!isempty(s)){
while(a){
//在这里输出是先序非递归
push(s,a);
a=a->left
}
if(!isempty(s)){
t=pop(s);
printf("%5d",a->data);
a=a->right;
}
}
}