//查找
一、顺序查找
顺序查找(Sequential Search) 又叫线性查找,是最基本的查找技术。
基本思想是从线性表的一端开始,逐个检查关键字是否满足给定的条件。
若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;
若已经查找到表的另一端,但还没有查找到符合给定条件的元素,则返回查找失败的信息。
typedef struct {
int *elem;
int length;
}SSTable;
int Search(SSTable ST,int key){
int i;
ST.elem[0]=key;
for(i=ST.length;ST.elem[i]!=key;--i)
return i;
}
二、折半查找
折半查找(Binary Search)技术,又称为二分查找。仅适用于有序的顺序表。
基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;
若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;
若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。
不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。
int HalfSearch(SSTable ST,int key){
int low=0,high=ST.length-1,mid;
while(low<=high){
mid=(low+high)/2;
if(ST.elem[mid]==key)
return key;
else if(ST.elem[mid]>key)
high=mid-1;
else
low=mid+1;
}
return false;
}
三、分块查找(索引顺序查找)
分块查找是一种用于提高查找效率的算法,特别适用于静态数据集。
其基本思想是将数据集划分为多个块(或段),然后在这些块中进行查找。
1.数据划分:将数据集分成若干个大小相等的块,每个块包含一定数量的元素。通常,块的大小是固定的。
2.块索引:为每个块维护一个索引,通常是块中第一个元素的值或块的最大值。这些索引可以帮助快速定位到可能包含目标元素的块。
3.查找过程:首先,通过比较目标值与块索引,确定目标值可能所在的块。然后,在确定的块内进行线性查找,找到目标值。
4.时间复杂度:分块查找的时间复杂度通常为 O(√n),其中 n 是数据集的大小。
5.适用场景:分块查找适用于静态数据集,特别是当数据集较大且查找操作频繁时,可以显著提高查找效率。
四、二叉排序树
二叉排序树(也称二叉查找树)或者是一棵空树,或者是具有下列特性的二叉树:
1.若左子树非空,则左子树上所有结点的值均小于根结点的值。
2.若右子树非空,则右子树上所有结点的值均大于根结点的值。
3.左、右子树也分别是一棵二叉排序树。
根据二叉排序树的定义,左子树结点值<根结点值<右子树结点值,所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列.
//二叉排序树的查找
BiTNode *BST_Search(BiTree T,int key){//非递归
while(T!=null &&key!=T->data){
if(key<T->data)T=T->lchild;
else T=T->rchild;
}
return T;
}
BiTNode *BST_Search(BiTree T,int key){//递归
if(T==null)return null;
if(key==T->data)
return T;
else if(key<T->data)
return BST_Serch(T->lchild);
else
return BST_Serch(T->rchild);
}
//二叉排序树的插入
int BST_Insert(BiTree &T,int k){
if(T==null){
T=new BiTNode;
T->data=k;
T->lchild=null;
T->rchild=null;
return true;
}
else if(k==T->data)
return 0;
else if(k<T->data)
return BST_Insert(T->lchild,k);
else
return BST_Insert(T->rchild,k);
}
//二叉排序树的构造
void Create_BST(BiTree &T,char str[],int k){
T=null;
int i=0;
while(i<k){
BST_Insert(T,str[i]);
++i;
}
}
二叉排序树的删除:
1.删除叶子节点:直接移除该节点。
2.删除只有一个子节点的节点:用其子节点替换被删除的节点。
3.删除有两个子节点的节点:找到被删除节点右子树中的最小节点(或左子树中的最大节点)来替换它,然后删除那个最小(或最大)节点。
平衡二叉树:
1.每一个节点的左子树和右子树的高度差至多等于1。
2.它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。
我们将二叉树上结点的左子树深度减去右子树深度的值称为平衡因子,那么平衡二叉树上所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。
五、散列表
1.散列表是根据关键字而直接进行访问的数据结构。也就是说,散列表建立了关键字和存储地址之间的一种直接映射关系
2.散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突。
3.这些发生冲突的不同关键字称为同义词
4.散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数。
5.常见的散列函数:
1)直接定址法
直接取关键字的某个线性函数值为散列地址
散列函数为H(key)=key或H(key)=a∗key+b式中,a和b是常数。这种方法计算最简单,且不会产生冲突。它适合关键字的分布基本连续的情况,若关键字分布不连续,空位较多,则会造成存储空间的浪费。
2)数字分析法
例如当手机号码为关键字时,其11位数字是有规则的,此时是无需把11位数值全部当做散列地址,这时我们给关键词抽取, 抽取方法是使用关键字的一部分来计算散列存储位置的方法,这在散列函数中是常常用到的手段。
数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀,就可以考虑用这个方法。这种方法适合于已知的关键字集合,若更换了关键字,则需要重新构造新的散列函数。
3)平方取中法
这个方法计算很简单,假设关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227,用做散列地址。再比如关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671,也可以是710,用做散列地址。平方取中法比较适合于不知道关键字的分布,而位数又不是很大的情况。
4)除留余数法
这是一种最简单、最常用的方法,假定散列表表长为m,取一个不大于m但最接近或等于m的质数p
利用以下公式把关键字转换成散列地址。散列函数为H(key)=key%p (p<=m)
5)随机数法
选择一个随机数,取关键字的随机函数值为它的散列地址。也就是
H(key)=random(key)这里random是随机函数。
6.处理冲突的方法
1、开放定址法
所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
1)线性探测法
2)平方探测法
3)双散列法
4)伪随机序列法
2.拉链法
第七章:查找
于 2024-09-06 19:27:16 首次发布