各类经典搜索算法(Search Algorithms)的简单介绍和C++实现

来源:互联网 发布:上古卷轴男性捏脸数据 编辑:程序博客网 时间:2024/06/15 17:12
/// <summary>/// 顺序搜索法(Sequential Search)/// 优点: 该方法对数据无事先排序(Sorting)要求, 容易实现/// 缺点: 搜索效率差(平均搜索 (N + 1) / 2 次), 不管是否排序, 每次都必须从头到尾遍历一次/// 时间复杂度: ///如果没有重复数据,线性查找在找到任一元素时就终止,否则需要全部遍历. 在最差情況下, 需作N次比较, O(N)///在平均狀況下(各元素出现与分布的概率相等)需 (N + 1) / 2次比较,所以最差时间为O(N), 最好时间为O(1) = 1次/// </summary>template<typename r = int> int sequential_search(const R *list, int n, const R &key){for (int i = 0; i < n; ++i){if (list[i] == key) return i;}// not foundreturn -1;}template<typename r = int> int sequential_search_last(const R *list, int n, const R &key){while (--n >= 0) {if (list[n] == key) return n;}// not foundreturn -1;}//-------------------------------------------------------------------------/// <summary>/// 二分搜索法(Binary Search)/// 优点: 搜索效率优(平均搜索 Log2N 次)/// 缺点: 数据必需事先排序且必需可直接随机存取/// 时间复杂度: ///每次比较都会比上一次少一半数据, 2^x = N, x = Log2N, 因此平均时间 O(LogN)/// </summary>template<typename r = int> int binary_search(const R *list, int n, const R &key){int _lower = 0;int _upper = n - 1;int _mean;while (_lower <= _upper) {_mean = (_lower + _upper) >> 1;if (list[_mean] == key) {return _mean;}if (list[_mean] > key) {_upper = _mean - 1;} else {_lower = _mean + 1;}}// not foundreturn -1;}template<typename r = int> int binary_search_recursion(const R *list, int _lower, int _upper, const R &key){assert(_lower <= _upper);int _mean = (_lower + _upper) >> 1;if (list[_mean] == key) {return _mean;}if (_lower == _upper){// not foundreturn -1;} //ifif (list[_mean] > key) {return binary_search_recursion(list, _lower, _mean - 1, key);}return binary_search_recursion(list, _mean + 1, _upper, key);}//-------------------------------------------------------------------------/// <summary>/// 插值搜索法(Interpolation Search)/// 定义: 二分搜索法的一种改进, 依照数据位置分布, 运用插值预测数据所在位置, 再以二分法方式逼近///       插值是离散函数逼近的重要方法, 利用它可通过函数在有限个点处的取值状况, 估算出函数在其他点处的近似值/// 优点: 数据分布均匀时搜索速度极快/// 缺点: 数据必需事先排序且需计算预测公式/// 时间复杂度: ///取决于数据分布情形, 平均时间 O(LogLogN) 优于 二分搜索 O(LogN)/// </summary>template<typename r = int> int interpolation_search(const R *list, int n, const R &key){int _lower = 0;int _upper = n - 1;int _mean;while (_lower <= _upper){// predictor_mean = (_upper - _lower) * (key - list[_lower]) / (list[_upper] - list[_lower]) + _lower;if (_mean < _lower || _mean > _upper) {// mean mispredictionbreak;}if (list[_mean] == key) {return _mean;}if (key < list[_mean]) {_upper = _mean - 1;} else {_lower = _mean + 1;}}// not foundreturn -1;}//-------------------------------------------------------------------------/// <summary>/// 斐波那契搜索法(Fbonacci Search)/// 定义: 利用斐波那契数列的性质(黄金分割原理)预测数据所在位置, 再以二分法方式逼近/// 优点: 只涉及加法和减法运算/// 缺点: 数据必需事先排序且需计算或者预定义斐波那契数列/// 时间复杂度: ///同于二分搜索 O(LogN), 平均情况下, 斐波那契查找优于二分查找, 但最坏情况下则劣于二分查找/// </summary>template<typename r = int> int fbonacci_search(const R *list, int n, const R &key){// 预定义斐波那契数列, 代码计算可参考http://blog.csdn.net/rrrfff/article/details/6848700static int F[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 };int _lower = 0;int _upper = n - 1;int _mean;// 计算 n 在斐波那契数列中位置int _index = 0;while (n > F[_index] - 1)++_index;// 斐波那契搜索要求 n == F[_index] - 1R *_list;int _count = F[_index] - 1;if (n != _count) {assert(n < _count);_list = new R[_count];memcpy_s(_list, _count * sizeof(R), list, n * sizeof(R));// 填补长度, _count则为填充后的长度for (int i = n; i < _count; ++i)_list[i] = _list[n - 1];} else {_list = const_cast<r>(list);} //ifwhile (_lower <= _upper) {// 利用斐波那契数列确定下一个要比较的元素位置_mean = _lower + F[_index - 1] - 1;if (key == _list[_mean]) {if (_list != list) delete[] _list;if (_mean <= n - 1)return _mean;elsereturn n - 1;} //ifif (key < _list[_mean]) {_upper = _mean - 1; // 待查找的元素在[_lower, _mean -1]范围内// 此时范围[_lower, _mean -1]内的元素个数为 F[_index - 1] - 1// 所以--_index;} else {_lower = _mean + 1; // 待查找的元素在[_mean + 1, _upper]范围内// 此时范围[_lower, _upper]内的元素个数为 _count - F[_index - 1] = //  (F[_index] - 1) - F[_index - 1] = (F[_index] - F[_index - 1]) - 1 = //   F(_index - 2) - 1个(因为 F(n) = F(n - 1) + F(n - 2)(n≥2, n∈N*))// 所以_index -= 2; }}if (_list != list) {delete[] _list;} //if// not foundreturn -1;}//-------------------------------------------------------------------------int _tmain(int argc, _TCHAR* argv[]){const int a[] = { 1, 3, 5, 18, 26, 39, 48, 66 };for each (auto k in a){int r1 = sequential_search(a, RLIB_COUNTOF(a), k);int r2 = sequential_search_last(a, RLIB_COUNTOF(a), k);int r3 = binary_search(a, RLIB_COUNTOF(a), k);int r4 = binary_search_recursion(a, 0, RLIB_COUNTOF(a) - 1, k);int r5 = interpolation_search(a, RLIB_COUNTOF(a), k);int r6 = fbonacci_search(a, RLIB_COUNTOF(a), k);printf(RLIB_NEWLINEA);}system("pause");}

此外, 还有


二元树搜索法(Tree Search):  先将数据列建立为一棵二元搜索树, 树中每节点皆不小于左子树(叶), 也不大于右子树(叶), 即有左子树的值≦树根值≦右子树的值.该方法的优点是插入与删除时, 只需改变指标, 且二叉树搜索效率较高(介于线性查找与二分之间,平均与最差时间为O(N) ).而缺点是除了要求数据有序外还需较多的额外內存来存储左右节点)

哈希搜索法(Hashing Search): 存取数据时, 并不依数据顺序存取, 而是将数据按照某特定法则(Hash映射)转换为数据储存位置(slot), 以数据键值(key-value)进行转换.【优点】1.搜寻速度最快; 2. 数据不必先排序; 3.在没发生碰撞(collision)与溢出(overflow)情况下, 仅需一次即可读取; 4.搜寻速度与数据量大小无关; 5.具有一定保密性, 若不知哈希函数, 无法取得数据存储位置(slot). 【缺点】1.浪费空间(有溢位数据区, 解决冲突), 且储存空间的利用率比线性存储差; 2.有碰撞问题, 当冲突太多时会严重影响速度; 3.程序设计略复杂; 4.大数据情况下效率不佳; 5.不适合挂载媒介.


等查找搜索算法,  因为该类算法涉及的知识点较多, 本篇便不进行阐述, 有兴趣者可以自行查阅资料并给予实现.


参考文献

搜尋(Search). http://spaces.isu.edu.tw/upload/18833/3/web/search.htm

原创粉丝点击