基本概念
查找表:有同一类型的数据元素构成的集合,数据元素间存在着松散的关系,没有严格的前驱后继关系。
查找:根据给定值在查找表中确定一个其关键字等于给定值的数据元素
关键字:用来标识一个数据元素的某个数据项的值
查找的成功:关键字等于给定的元素
查找的操作: 存在性确定,检索属性,插入元素,删除元素
查找表的分类:静态查找表,动态查找表
评价指标:平均查找长度ASL
研究内容:查找表的组织方式以及如何提高查找效率
线性表的查找
顺序查找(线性查找)
线性表上的静态查找,表内元素可无序
struct SSTable{
int *arr;
int len;
}
在顺序表中查找值为key的数据元素
算法:
//查找成功返回下标,失败返回0,表头作为哨兵
int Search_Seq(SSTable ST,int key){
ST.arr[0] = key;
int i;
for(i = ST.len;ST.arr[i] != key;i--) ;
return i;
}
比较次数:n-i+1,查找失败查找n+1次
ASL:(n+1)/2
时间复杂度:n
空间复杂度:1
如何提高查找效率:
- 被查找概率高的放前面
- 俺查找概率动态调整顺序:每个结论中加入访问频度域,俺非递增排列,每次查很早后均将刚查到的记录移至表头
优点:算法简单,逻辑次序存储结构无要求
缺点:时间效率低
折半查找(二分查找)
每次讲带查找记录所在区间缩小一半
mid = (left + right) / 2
key < mid:right = mid - 1
key > mid:left = mid + 1
key = mid:找到
right < left:结束
算法(非递归):
int Search_Bin(SSTable ST,int key){[
int left = 1,right = n,mid = (left + right) / 2;
while(l <= r){
mid = l + r / 2;
if(ST.arr[mid] == key)return mid;
else if (key < ST.arr[i]) r = mid - 1;
else l = mid + 1;
}
return 0;
}
递归算法:
int Search_Bin(SSTable ST,int key,int l,int r){
if(l > r)return 0;
mid = (l + r) / 2;
if(key == ST.arr[mid]) return mid;
else if (key < ST.arr[mid])Search_Bin(ST,key,l,mid - 1);
else Search_Bin(ST,key,mid + 1,r);
}
判定树:
比较次数 = 路径上的节点数 = 节点的层数 <= 树的深度 = log2^n + 1
ASL = (n + 1) / n log2^(n+1) - 1
约等于log2^(n+1) - 1 (n>50)
时间复杂度:lgn
优点:效率比顺序查找高
缺点:只适用于有序表,且限于顺序存储结构
分块查找(索引顺序表查找)
条件:表中分成若干块,分块有序,块内可无序
查找过程:先确定所在块,再在块内查找
n个元素,s块
ASL = log 2(n/s+1) + s/2
快于顺序查找,略慢与二分查找
优点:插入删除较容易
缺点:增加索引表所需空间
适用情况:线性表要快速查找还要动态变化
查找方法的比较
树表的查找
表的插入删除操作频繁,为维护表的有序性,改用动态查找表——特殊的树
表结构在查找过程中动态生成
二叉排序树
性质:
- 若左子树非空,则左子树上所有节点的值均小于根节点的值
- 若右子树非空,则右子树上所欲节点的值均大于等于根节点的值
- 其左右子树本身是一颗二叉排序树
查找
struct BSTNode{
int data;
BSTNode *l,*r;
}
算法思想:
若二叉排序树为空,查找失败,返回空指针;
若二叉排序树非空,讲key与根节点的值相比较:
==,查找成功,返回根节点地址;
《,找左子树
》,找右子树
BSTree SearchBST(BSTree T,int key){
if( !T || key == T->data) return T;
else if(key < T->data) return Search BST(T->l,key);
else return SearchBST(T->r,key);
}
查找分析:
含有n个节点的二叉排序树的平均查找长度和树的形态有关
完全二叉树:log2^n
单支二叉树:n
如何提高查找效率:平衡化处理
插入
若二叉排序树为空,则插入节点作为根节点插入空树中
否则,继续在左右子树上查找
树中有,不再插入
树中没有,查找直到某叶子节点的左子树或右子树为空为止,则插入节点为其孩子节点
生成
从空树除法,经过一系列的查找、插入操作之后,生成一颗二叉排序树
关键字输入顺序不同,生成的二叉排序树不同
删除
不饿能把以该节点为根的子树都删去,删除后二叉树仍然满足二叉排序树
- 删除叶子节点:直接删,其父节点的子节点为空
- 只有左子树或右子树:用其左子树或右子树替换他
- 左右子树都有:前驱节点(左子树中最大的节点)代替他,前驱节点原位置删除;后继节点代替(右子树中最小的节点)
注意:可以减小树的高度的优先
平衡二叉树(AVL)
是空树或者有下列性质的二叉排序树:
- 左子树与右子树的高度差的绝对值小于等于1
- 左子树和右子树也是平衡二叉排序树
平衡因子(BF) = 节点左子树高度-节点右子树高度
构造
失衡二叉排序树的分析与调整
在平衡二叉树中查如一个系欸但时,可能导致失衡,即出现平衡因子绝对值大于1的节点,必须重新调整树的结构使之回复平衡。
平衡调整:
失衡的节点不止一个:找最小失衡子树的根节点
调整原则:降低高度;保持二叉排序性质
从上到下分别是ABC
LL型:
B节点的左子树上升,A节点成为B节点的右孩子,原来b节点的右子树作为A的左子树
RR型:
B节点带右子树一起上升,A成为B的左孩子,原B节点的左子树作为A的右子树
LR型:
C上升,B成为C的左孩子,A成为C的右孩子,C原来的左子树变为B的右子树,C原来的右子树变为A的左子树
RL型:
C上升,A成为C的左孩子,B成为C的右孩子,C原来的左子树成为A的右子树,C原来的右子树成为B的左子树