1 概念
查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合。
查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
查找表按照操作方式可以分为两大种:静态查找表和动态查找表。
(1)静态查找表:只做查找操作的查找表。
(2)动态查找表:在查找的过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。
2 有序表查找
(1)折半查找(二分查找)
折半查找的前提是线性表中的记录必须是关键码有序(通常从小到大排序),线性表必须采用顺序存储。
//折半查找 int Binary_Search(int *a, int n, int key) { int low, high, mid; low = 1; //定义最低下标的记录首位 high = n; //定义最高下标的记录末位 while(low <= high) { mid = (low + high)/2; if (key < a[mid]) { high = mid - 1; } else if (key > a[mid]) { low = mid + 1; } else { return mid; } } return 0; }
(2) 插值查找
折半查找的mid = (low + high)/2 = low + (high - low) * (1/2),也就是mid等于最低下标low加上最高下标high与最低下标low的差的一半。算法科学家将(1/2)改进为(key - a[low])/ (a[high] - a[low]).
对于表长较大,而关键字分布比较均匀的查找表来说,插值查找的性能比折半查找的性能要高很多。反之,若查找表中的数据{1,2,3,200,300, ..., 8000,9000}分布极度不均匀,则
插值查找未必是很好的选择。
(3) 斐波那契查找
//斐波那契查找 int Fibonacci_Search(int *a, int n, int key) { int low, high, mid, i, k; low = 1; high = n; k = 0; while (n > F[k] - 1) { //计算n位于斐波那契数列的位置 k ++; } for (i = n; i < F[k] - 1; i ++) { //将不满的数值补全 a[i] = a[n]; } while (low <= high) { mid = low + F[k - 1] - 1; //计算当前分割的下标 if (key < a[mid]) { high = mid - 1; //最高下标调整到分割下标mid-1处 k = k - 1; //斐波那契数列下标减1 } else if (key > a[mid]) { low = mid + 1; //最低下标调整到分割下标mid+1处 k = k - 2; //斐波那契数列下标减2 } else { if (mid <= n) { return mid; //若相等则说明mid即为查找到的位置 } else { return n; //若mid > n, 说明是补全数值,返回n } } } return 0; }
3 三种查找方法比较
折半查找是进行加法和除法运算 mid = low + (high - low)/2, 插值查找是进行复杂的四则运算 mid = low + (high - low) * (key - a[low])/(a[high] - a[low]), 而斐波那契查找只是最简单的加减法运算 mid = low + F[k - 1] - 1, 在海量数据的查找过程中,这种细微的差别可能会影响最终的查找效率。
三种查找的本质区别是分隔点的选择不同,各有优劣,实际开发中可根据数据的特点综合考虑后再做决定。