目录
基本概念
根据给定的一个值,在查找表中确定一个关键字等于给定值的数据元素或(记录)
关键字:用来标识一个数据元素(或记录)的某个数据项的值
主关键字:可唯一地标识一个记录的关键字是主关键字
次关键字:用以标识若干记录的关键字是次关键字
线性表的查找
顺序查找(线性查找)
应用范围
- 顺序表或线性链表表示的静态查找表
- 表内元素之间无序
顺序表的数据元素类型定义
typedef struct{
KeyType key; //关键字域
…… //其他域
}ElemType;
顺序表的表示
typedef struct{ //顺序表结构类型定义
ElemType *R; //基地址
int length; //表长
}SSTable;
SSTable ST; //定义顺序表ST
顺序查找算法 O(n)
int Search_Seq(SSTable ST,KeyType key){
//若成功返回其位置信息,否则返回0
for(i=ST.length;i>=1;--i)
if(ST.R[i].key == key) return i;
return 0;
}
设置监视哨的顺序查找 O(n)
int Search_Seq(SSTable ST,KeyType key){
//在顺序表ST中顺序查找其关键字等于key的数据元素
ST.R[0].key=key; //"哨兵"
for(i=ST.length;ST.R[i].key!=key;--i);
return i;
}
查找第i个元素,需要比较n-i+1次;查找失败,需比较n+1次。
平均查找长度(n+1)/2
空间复杂度为O(1)
顺序查找的优缺点
优点:算法简单,对表结构无任何要求,既适用于顺序结构,也适用于链式结构,无论记录是否按关键字有序均可应用。
缺点:平均查找长度较大,查找效率较低,所以当n很大时,不宜采用顺序查找
折半查找(二分查找) O(log2n)
mid = (low + high)/2
折半查找的算法
int Search_Bin(SSTable ST,KeyType key){
low = 1;high = ST.length; //置区间初值
while(low <= high){
mid = (low+high)/2;
if(ST.R[mid].key == key) return mid;
else if(key < ST.R[mid].key)
high = mid-1;
else low = mid+1;
}
return 0;
}
折半查找的递归算法
int Search_Bin(SSTable ST,keyType key, int low,int high){
if(low > high) return 0;
mid = (low + high)/2;
if(key == ST.elem[mid].key) return mid;
else if(key < ST.elem[mid].key)
Search_Bin(SSTable ST,keyType key, int low,int mid-1);
else
Search_Bin(SSTable ST,keyType key, int mid+1,int high);
}
折半查找的判定树
时间复杂度为O(log2n)
平均查找长度ASL=log2(n+1)-1
折半查找的优缺点
优点:效率比顺序查找高
缺点:只适用于有序表,且限于顺序存储结构(对线性链表无效)
分块查找
优点:插入和删除比较容易,无需进行大量移动
缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算
适用情况:如果线性表既要快速查找又经常动态变化,则可采用分块查找
查找方法比较
树表的查找
动态查找表–对于给定值key,若表中存在,则成功返回;否则,插入关键字等于key的记录
二叉排序树
二叉排序树或是空树,或是满足以下性质的二叉树
- 若其左子树非空,则左子树上所有结点的值均小于根结点的值
- 若其右子树非空,则右子树上所有结点的值均大于等于根结点的值
- 其左右子树本身又是一棵二叉排序树
中序遍历非空的二叉排序树是一个按关键字排列的递增有序的序列
比较的关键字次数=此结点所在层次数
最多的比较次数=树的深度
二叉排序树的存储结构
typedef struct{
KeyType key; //关键字项
InfoType otherinfo; //其他数据域
}ElemType;
typedef struct BSTNode{
ElemType data; //数据域
struct BSTNode *lchild,*rchild; //左右孩子指针
}BSTNode,*BSTree;
BSTree T; //定义二叉排序树T
二叉排序树的查找操作 O(log2n)
BSTree SearchBST(BSTree T,KeyType key){
if((!T)|| key == T->data.key) return T;
else if(key < T->data.key)
return SearchBST(T->lchild,key); //在左子树中继续查找
else return SearchBST(T->rchild,key); //在右子树中继续查找
}
含有n个结点的平均查找长度最好情况:O(log2n)
最坏情况:O(n)
二叉排序树的插入操作 O(log2n)
插入的元素一定在叶结点上
void InsertBST(BSTree &T,ElemType e){
//当二叉排序树T中不存在关键字等于e.key的数据元素时,则插入该元素
if(!T){
S = new BSTNode; //生成新结点*S
S -> data = e;
S -> lchild = S -> rchild = NULL; //新结点*S作为叶子结点
T = S;
}
else if(e.key < T -> data.key)
InsertBST(T -> lchild,key);
else if(e.key < T -> data.key)
InsertBST(T -> lchild,key);
}
二叉排序树的创建操作 O(nlog2n)
不同插入次序的序列生成不同形态的二叉排序树
void CreateBST(BSTree &T){
//依次读入一个关键字为key的结点,将结点插入二叉排序树T中
T = NULL;
cin >> e;
while(e.key != ENDFLAG){ //ENDFLAG为自定义常量,作为输入结束标志
Insert(T,e);
cin >> e;
}
}
二叉排序树的删除操作
①被删除的结点是叶子结点:直接删去该结点
②被删除的结点只有左子树或者只有右子树,用其左子树或者右子树替换它(结点替换)
③若被删除的结点既有左子树,又有右子树,则用其中序前驱结点的值代替它(前驱是左子树中最大的结点),然后再删除该前驱结点;也可以用其后继替换之,然后再删除该后继结点,后继是右子树中最小的结点
平衡二叉树 AVL树
①左子树和右子树的深度之差的绝对值不超过1
②左子树和右子树也是平衡二叉排序树
若将二叉树上结点的平衡因子(BF)定义为该结点左子树和右子树的深度之差,则平衡二叉树上所有结点的平衡因子只可能是-1,1,0
对于一个有n个结点的AVL树,其高度保持在O(log2n)数量级,ASL也保持在O(log2n)量级
失衡二叉排序树的调整原则
①降低高度
②保持二叉排序树性质
散列表的查找
直接定址法
Hash(key) = a*key + b (a,b为常数)
优点:以关键码key的某个线性函数值为散列地址,不会产生冲突
缺点:要占用连续的地址空间,空间效率低
除留余数法
Hash(key) = key mod p (p是一个整数,且是一个质数 p <= 表长m)
处理冲突的方法
开放地址法
基本思想:有冲突时就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将数据元素存入
线性探测法
一旦冲突,就找下一个地址,直到找到空地址存入
链地址法
0-12(13种可能,所以需要mod13)
优点
①非同义词不会冲突,无“聚集”现象
②链表上结点空间动态申请,更适合于表长不确定的情况
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/83248.html