最近在看<大话数据结构>,这本书真是写的好呀呀呀,关于查找做了些笔记.
一.顺序表查找
1. 顺序查找
也称为线性查找,查找过程基本是从第一个(或最后一个)开始查找,逐个与查找值的关键字对比是否相等,若相等查找成功,若到最后都没有没有相等,则查找失败.
时间.
顺序查找优化:即设定一个哨兵,解决了不用每次都要比较.
时间复杂度:O(N).
int SequentialSearch(int*a, int n, int key)
{
a[0] = key;
int i= sizeof(a)/sizeof(int) - 1;
//因a[0] =key设定了是哨兵;,当i==0时,a[0]与key必定相等.这也是哨兵的作用.
while(a[i] != key)
{
i --;
}
return i;
}
二. 有序表查找(查找的数据是有序的)
※ 包括折半, 插值, 斐波那契查找.
1. 折半查找
又称二分查找,前提是查找表是有序的.
时间复杂度:O(logN).
查找过程:(1)在有序表中,取中间值mid与关键字key进行比较,如果mid与key相等,则查 找成功.如果mid < key, 则(2), 如果mid > key,则(3).
(2)取mid的左半端(不包括(1)mid)的中间值,转(1).
(3)取mid的有半段(不包括之前(1)mid)的中间值,转(1).
int BinarySearch(int *a, int n, int key)
{
intlow, mid, high;
low= 1;
high= n;
while(low<= high)
{
mid = (low + high)/2;
if (a[mid] < key)
{
low= mid + 1;
}
else if(a[mid] > key)
{
high= mid - 1;
}
else
{
returnmid;
}
}
return0;
}
2. 插值查找
折半查找是折取一半,而插入查找是折取更多(如1/4).
折半:mid =(high - low)/2 = low + 1/2*(high - low).
插入: mid = low + (key - a[low])/(high - a[low)*(high - low).将1/2进行改进.
即, (把1/2换成(key - a[low])/(high - a[low)).
时间复杂度:O(logN).
比较:插值查找是根据关键字与查找表中最大最小记录的关键字比较后的查找方法,其核心是插值的计算公式: (key- a[low])/(high - a[low).对于表较长且关键字分布较均匀来说,插值查找算法的平均性能比二分查找好很多.反之,如果是不均匀的数据,就不适合用插值查找了.
3. 斐波那契查找
F(n)=F(n-1)+F(n-2), F(0)=1,F(1)=1.(斐波那契数列)
int FibonacciSearch(int*a, int n, int key)
{
int low,mid, high, i, k;
low = 1;
high = n;
k = 0;
while(n> F[k] - 1)
{
++k;
}
for(i =n; i < F[k]-1; ++i)
{
a[i] = a[n];//将不满的数组补全.
}
while(low<= high)
{
mid = low + F[k] - 1;
if(key < a[mid])//之后只需要查找范围是右半部份.
{
high = mid - 1;
k = k - 1;
}
elseif (key > a[mid]) 之后只需要查找范围是左半部份.
{
low = mid + 1;
k = k - 2;
}
else
{
if (mid <= n)
{
return mid;
}
else
{
return n;
}
}
}
return 0;
}
时间复杂度:O(logN).
如果查找的数据在一侧,那么另一侧数据就不用判断了,如此反复,对于大部分数据是效率高的,就平均性能来说由于折半.但是如果key=1,查找始终在左侧长半区,那么效率就会低于折半
比较:关键的一点是,折半查找是进行加法和除法运算:mid=(low+high)/2,而插值进行复杂的四则运算: low+ (key - a[low])/(high - a[low)*(high - low),然而斐波那契需加减算法mid=low+F[k-1]-1,如果是在海量的数据中查找,那么这种细微的差别可能会影响查找效率,而斐波那契更适合.
三. 线性索引查找
很多海量的数据要按照某个关键字有序存储,其时间代价是很昂贵的,这种数据一般都是按照先后顺序存储的.
数据结构最终的目的是提高处理数据的速度.索引就是是为了加快查找而设计的一种数据结构.
索引就是把一个关键字与它对应的记录相关联的过程.一个索引有若干由若干个索引项构成,每个索引项至少应包含关键字和其对应记录在存储器的位置.
索引分类:线性索引, 树形索引, 多级索引.
线性索引(索引表): 将索引项集合组织委线性结构.
1. 稠密索引
是指在线性索引中,将数据集中的每个记录对应一个索引项.(一一对应.)
对于稠密索引的这个索引表来说,索引项一定是按照关键字来有序排列的.
既然索引项是有序的,那么我我就可以用折半, 查值, 斐波那契等有序算法来查找,大大提高效率.我们可以通过查找索引表来得到相对应的指针,最终得到查找结果.
但是如果数据集非常大,对于数据集长度的规模,计算机内存有限,可能就需要反复的去访问磁盘,查找性能反而降低.
2. 分块索引
稠密索引因为索引项与数据集的记录个数(一一对应的),所以空间代价也很大,为了减少索引项个数,我们可以对数据集进行分块,使其分块有序,然后对每个块建立一个索引项,从而减少索引项的个数.
即分块是有序的,把数据集分成若干个块,块内是无序的,块间是有序的只有块间有序才会带来查找时的效率.
分块索引:是将分块有序的数据集,每块对应一个索引项.
索引项结构分3个数据项,分别为:
(1) 最大关键码:它存储每一块的最大关键字,好处是使它的下个块的最小关键字>此最大关键字
(2) 块个数;
(3) 指针:指向块首元素.
※在分块索引表中是有序的,故可以利用折半,插值等来查找得到块的首元素指针,以便在块表中用顺序查找.
比较:分块索引查找比顺序查找O(N)效率高不少,但是塔与折半查找O(logN)还有不小差距.所以在块间有序,应折半,插值来提高效率.
总体来说,分块索引兼顾了对细分块不需要有序的情况下,大大提高查找速度.呗普遍用于数据库表查找等技术.
==================================================