查找
根据某个给定关键字K,从集合R中找出关键字与K相同的记录
- 静态查找:集合记录是固定的->没有插入和删除操作,只有查找
- 动态查找:集合中记录是动态变化的->除查找,还可能发生插入和删除
静态查找
- 顺序查找,时间复杂度为O(n)
int SequentialSearch(StaticTable *Tbl,ElementType K){
//在表Tbl[1]~Tb1[n]中查找关键字为K的数据元素
int i;
Tb1->Element[0]=K;//建立哨兵,让数组下标为0的位置的值为K
for(i=Tb1->Length;Tb1->Element[i]!=K;i--);
return i;//查找成功返回所在位置下标,不成功返回0
- 二分查找,时间复杂度为O(logN)
假设n个数据元素的关键字满足有序并且是连续存放就可以进行二分查找
int BinarySearch(StaticTable *Tbl,ElementType K){
//在表Tbl中查找关键字为K的数据元素
int left,right,mid,NoFound=-1;
left=1; //初始左边界
right=Tbl->Length; //初始右边界
while(left<=right){
mid=(left+right)/2; //计算中间元素坐标
if(K<Tbl->Element[mid]) right=mid-1;//调整右边界
else if(K>Tbl->Element[mid]) left=mid+1; //调整左边界
else return mid; //查找成功,返回数据元素的小标
}
return NotFound; //查找不成功,返回-1
}
二分查找判定树
- 判定树上每个结点需要的查找次数为该结点所在的层数
- 查找成功时查找次数不会超过判定树的深度
- n个结点的判断树的深度为[log2(n)]+1
- 平均查找次数(ASL) 每一层的结点个数乘以层数
树的定义
n个结点构成的有限集合 当n=0时称为空树
- 对于任一棵非空树(n>0) 具备以下性质:
- 树中有一个称为“根”的特殊结点,用r表示;
- 其余结点可分为m(m>0个互不相交的有限集T1,,Tn,其中每个集合本身又是一棵树,称为原来树的“子树”
- 子树互不相交
- 除了根结点外,每个结点有且仅有一个父结点
- 一棵N个结点的树有N-1条边
树的基本用语
- 结点的度(Degree):结点的子树个数
- 树的度:树的所有结点中最大的度
- 叶结点(Leaf):度为0的结点
- 父结点(Parent):有子树的结点是其子树的根结点的父结点
- 子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点;子结点也称孩子结点
- 兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点
- 路径和路径长度:从结点n1到nk的路径为一个结点序列n1,,,,nk,ni是ni+1的父结点。路径所包含边的个数为路径长度
- 祖先结点(Ancestor):沿树根到某一结点路径上的所有结点都是这个结点的祖先结点
- 子孙结点:某一结点的子树中的所有结点是这个结点的子孙
- 结点的层次:规定根结点在1层,其它任一结点的层数是其父结点的层数加1
- 树的深度(Depth):树中所有结点中的最大层次是这棵树的深度
二叉树及存储结构
- 二叉树的定义
一个有穷的结点的集合 这个集合可以为空;若不为空,则它是由根结点和称为其左子树T[L]和右子树T[R]的两个不相交的二叉树组成
- 二叉树有左右之分
特殊的二叉树
- 斜二叉树
- 完美二叉树/满二叉树
- 完全二叉树
有n个结点的二叉树,对树中结点按从上至下,从左到右的顺序进行编号,编号为i(1<=i<=n)结点与满二叉树中编号为i结点在二叉树中位置相同 完全二叉树是完美二叉树的子集,而且是连续不断的那种
二叉树的几个重要性质
- 一个二叉树第i层的最大结点数为:2^(i-1),i>=1;
- 深度为K的二叉树有最大结点总数为:2^(k)-1,k>=1
- 对任何非空二叉树T,若n[0]表示叶结点的个数,n[2]是度为2的非叶结点个数,那么两者满足关系n[0]=n[2]+1
二叉树的抽象数据类型定义
- 操作集
1. Boolean IsEmpty(BinTree BT):判别BT是否为空
2. void Traversal(BinTree BT):遍历,按某顺序访问每个结点
3. BinTree CreatBinTree():创建一个二叉树
- 常用遍历方法
1. void PreOrderTraversal(BinTree BT):先序--根,左子树,右子树
2. void InOrderTraversal(BinTree BT):中序--左子树,根,右子树
3. void PostOrderTraversal(BinTree BT):后序--左子树,右子树,根
4. void LevelOrderTraversal(BinTree BT):层次遍历,从上到下,从左到右
二叉树的存储结构
顺序存储结构
- 完全二叉树
按从上至下,从左到右的顺序存储n个结点的完全二叉树的结点父子关系
- 一般二叉树采用上述结构会造成很大的空间浪费
链表存储
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
二叉树遍历
先序遍历中序遍历后序遍历其实差距不大 访问根结点的顺序不一样
- 递归遍历
//先序遍历
//1.访问根结点
//2.先序遍历左子树
//3.先序遍历右子树
void PreOrderTraversal(BinTree BT){
if(BT){
printf("%d",BT->Data);
PreOrderTraversal(BT->Left);
PreOrederTraversal(BT->Right);
}
}
//中序遍历
//1.中序遍历左子树
//2.访问根结点
//3.中序遍历右子树
void InOrderTraversal(BinTree BT){
if(BT){
InOrderTraversal(BT->Left);
printf("%d",BT->Data);
InOrderTraversal(BT->Right);
//后序遍历
//1.后序遍历左子树
//2.后序遍历右子树
//3.访问结点
void PostOrderTraversal(BinTree BT){
if(BT){
PostOrderTraversal(BT->left);
PostOrderTraversal(BT->Right);
printf("%d",BT->Data);
}
}
- 先序中序后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同
非递归遍历算法
- 中序遍历非递归算法
- 遇到一个结点,就把它压栈,并去遍历它的左子树
- 当左子树遍历结束后,从栈顶弹出这个结点并访问它
- 然后按其右指针再去中序遍历该结点的右子树
void InOrderTraversal(BinTree BT){
BinTree T=BT;
Stack S = CreatStack(MaxSize);
while(T||!TsEmpty(s)){
while(T){ //一直向左并将沿途结点压入堆栈
Push(S,T);
T=T->Left;
}
if(!TsEmpty(s)){
T=Pop(S); //结点弹出堆栈
printf("%5d",T->Data); //打印结点
T=T->Right; //转向右子树
}
}
}
- 先序遍历非递归算法
void InOrderTeaversal(BinTree BT){
BinTree T BT;
Stack S=CreatStack(MaxSize);
while(T||!IsEmpty(S)){
while(T){
Push(S,T);
T=T->Left;
}
if(!IsEmpty(S)){
T=Pop(S);
T=T->Right;
}
}
}
层序遍历
- 队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队,访问该结点,其左右儿子入队
//从队列中取出一个元素
//访问该元素所指结点
//若该元素所指结点的左右孩子结点非空,则将其左右孩子的指针顺序入队
void LevelOrderTraversak ( BinTree BT ){
Queue Q;BinTree T;
if ( !BT ) return;
Q = CreatQueue ( MaxSize );
AddQ ( Q,BT );
while ( !IsEmptyQ ( Q ) ){
T = DeleteQ( Q );
printf("%d
",T->Data);
if (T->Left) AddQ(Q,T->Left);
if (T->Right)AddQ(Q,T->Right);
}
}
- 遍历二叉树的应用,输出二叉树中的叶子结点
void PreOrderPrintLeaves (BinTree BT){
if(BT){
if(!BT->Left && !BT->Right){
printf("%d",BT->Data);
PreOrderPrintLeaves (BT->Left);
PreOrderPrintLeaves (BT->Right);
- 求二叉树的高度
//Height=max(Hl,Hr)+1
int PostOrderGetHeight(BinTree BT){
int HL,HR,MaxH;
if(BT){
HL=PostOrderGetHeight(BT->Left);
HR=PostOrderGetHeight(BT->Right);
MaxH=(HL>HR)?HL:HR;
return (MaxH+1);
}
else return 0;
}
- 二元运算表达式树及其遍历
1. 先序遍历得到前缀表达式
2. 中序遍历得到中缀表达式(得到的中缀表达式可能会改变原表达式的意思)
3. 后序遍历得到后缀表达式
- 可有中序遍历和其他两种遍历中的任意一种共同确定一个二叉树
1. 根据先序遍历序列第一个结点确定根结点
2. 根据结点在中序遍历序列中分割出左右两个子序列
3. 对左右子树分别递归使用相同的方法继续分解