一、顺序查找表
1.顺序查找表:
顺序查找的过程为:从表的一端开始扫描,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,找到所查记录;反之,若直至表的另一端,其关键字和给定值比较都不等,则表明表中没有所查记录,查找不成功。
2 . 算法分析:
(1) 在最坏的情况下,顺序查找需要比较 n 次,即 MSL = n 。
(2) 最好的情况是第一个元素即为目标元素,最坏情况是最后一个元素为目标元素,平均情况是与线性表中一半的元素比较。
(3) 假定各记录的查找机会均等,即 P i = 1/n ,由于查找第 i 个记录需要比较 i 次,即 C i = i ,于是有:
ASL = (n+1)/2;
这样,最大查找长度和平均查找长度的数量级 ( 即算法的时间复杂度 ) 均为 O(n) 。
3 . 顺序查找的优点和缺点:
优点:该算法比较简单且适用面比较广,它对表的结构无任何要求,无论记录是否按关键字有序均可应用。
缺点:平均查找长度比较大,特别是当n值很大时查找效率较低。
4.算法实现_C++:
#include<iostream>
using namespace std;
typedef struct node{
int date[100];
}LinkNode
int main(){
LinkNode p;
int i,n,schar,set = 0;
cout<<"请输入要输入多少个数据"<<endl;
cin>>n;
cout<<"请往表中输入数据"<<endl;
for(i=0;i<n;i++){
cin>>p.date[i];
}
cout<<"请输入您要查找的数据"<<endl;
cin>>schar;
for(i=0;i<n;i++){
if(p.date[i] == schar){
cout<<"您要查找的数据存在表中"<<endl;
set == 1;
break;
}
}
if(set == 0){
cout<<"您要查找的数据表中不存在"<<endl;
}
}
二、有序表的查找(二分查找)
1.二分查找表:
对于以数组方式存贮的记录,如果数组中各个记录的次序是按其关键字值的大小顺序排列的,则称为有序数组或有序表。形如:05 13 19 21 37 56 64 80。 对有序表采用二分查找。
2.查找过程:
首先将待查找的k值和有序表R中间的位置 mid=(low+high)/2上关键字进行比较:
(1) 若相等,则查找成功;
(2) 若R[mid].key>k,则说明待查找的结点在表的前半部分,可缩小范围,在表的前半部分[low,mid-1]继续进行二分查找;
(3) 若R[mid].key< k,则说明待查找的结点在表的后半部分,可缩小范围,在表的后半部分[mid+1,high]继续进行二分查找;
这样经过一次关键字的比较就缩小一半的查找区间;如此反复,直到找到关键字为k的结点(查找成功),或当前的查找区间为空(查找失败)。
3.平均查找长度:
折半查找的过程实际上是从二叉树的根结点开始到该记录结点的查找过程。因此,比较的次数不超过二叉树的深度 d = [log2 n ] + 1 。特别地,当 n = 2 d -1 时,描述折半查找的二叉树一定是深度为 d 的满二叉树。查找第 1 层 ( 根结点 ) 的记录仅需一次比较,且只有一个记录。查找第 i 层 (1 ≤ i < d) 记录需做 i 次比较,第 i 层有 2 i-1 个记录。假定每个记录的查找概率相等,即 P i = 1/n ,则平均查找长度为:
ASL = Ci*Pi=1/n(C1+C2+C3+…..)=1/n(1+2*2+3*22+…+(d-1)*2d-2+d*L)式中, L 为叶结点个数, 1 ≤ L ≤ 2d-1 , n = 2d-1-1+L。
当n较大(n>50)时,可有下列近似的结果,ASL=log2(n+1)-1;
所以,折半查找的平均查找长度数量级 ( 算法时间复杂度 ) 亦为 O (log2 n ) 。
(详见《数据结构(C语言版)》严蔚敏,第220页)
4.算法分析_C:
int BinSearch(table R[], int n, KeyType k){
int low,high,mid;
low = 1; high = n;
while(low<=high){
mid = (low+high)/2;
if(k == R[mid].key)
return mid;
if(k > R[mid].key)
high = mid + 1;
else
low = mid + 1;
}
}
5.二分查找的优缺点:
优点:查找效率高,查找速度快,比较次数少,平均性能好;
缺点:待查表必须为已经排好序的有序表,并且要用顺序表做为存储结构,插入删除较困难。
因此,二分查找特别适用于那种一经建立就很少改动、而又经常需要查找的线性表。对那些查找少而又经常需要改动的线性表,可采用链表作存储结构,进行顺序查找。链表上无法实现二分查找。
三、索引顺序表查找(分块查找)
1.分块查找:
分块查找又称索引顺序查找,是一种介于顺序查找和二分查找之间的查找方法。 分块查找要求将查找表分成 若干个子表,并对子表建立索引表,查找表的每一个子表由索引表中的索引项确定。索引项包括两个字段:关键码字段(存放对应子表中的最大关键码值) ;指针字段(存放指向对 应子表的指针) ,并且要求索引项按关键码字段有序。查找时,先用给定值key 在索引表中 检测索引项,以确定所要进行的查找在查找表中的查找分块(由于索引项按关键码字段有序,可用顺序查找或折半查找) ,然后,再对该分块进行顺序查找。
2 查找过程:
分块查找的函数分为如下两步:
a)首先确定待查找的结点属于哪一块,即查找所在的块;(顺序查找或分块查找均可)
b)然后,在块内查找要查的结点。(顺序查找)
设表共n个结点,分b块,s=n/b
(分块查找索引表)平均查找长度=Log2(n/s+1)+s/2
(顺序查找索引表)平均查找长度=(S2+2S+n)/(2S)
3.优缺点分析:
优点:在表中插入或删除一个记录时,只要找到该记录所属的块,就在该块中进行插入或删除运算。因块内记录的存放是任意的,所以,插入或删除比较容易,无需移动大量记录。效率大于顺序查找,小于二分查找。
缺点:主要代价是需要增加一个辅助数组存储索引表和对初始表进行分块排序建立索引表的运算。
4.算法实现_C++:
#include<iostream>
using namespace std;
#define MAX 16
typedef int key_type;
struct elem
{
key_type key; //关键字
};
//索引结构
struct index
{
key_type key; //索引值
long low; //起始位置
long high; //终止位置
};
int index_search(elem e[], key_type key, int n, index idx[], int idx_length)
{
int low = 0;
int high = idx_length - 1;
int mid;
//采用折半查找在索引表里找到关键字所在的块
while(low <= high)
{
mid = (low + high)/2;
if(key < idx[mid].key)
high = mid - 1;
else if(key > idx[mid].key)
low = mid + 1;
else
break;
}
//采用顺序查找的方法从块中查找关键值
int i = idx[mid].low;
while(i <= idx[mid].high && e[i].key != key)
{
i++;
}
if(i > idx[mid].high)
return -1;
else
return i;
}
int main(int argc, char** argv)
{
elem linelist[MAX] = {
8, 20, 13, 17,
40, 42, 45, 32,
49, 58, 50, 52,
67, 79, 78, 80
};
int n = sizeof(linelist) / sizeof(elem);
key_type key = 50;
//建立索引表
index index_table[4] = {{20,0,3}, {45,4,7}, {58,8,11}, {80,12,15}};
int idx_length = sizeof(index_table) / sizeof(index);
printf("线性表中的元素为:\n");
int i = 0;
while(i < n)
{
printf("%d\n",linelist[i].key);
i++;
}
printf("\n关键字[%d]在线性表中的位置下标为[%d]", key, index_search(linelist, key, n, index_table, idx_length));
getchar();
system("pause");
}