zoukankan      html  css  js  c++  java
  • 搜索查找算法实现合集-经典搜索算法实现与分析:顺序查找,二分查找,分块查找;广度优先搜索,深度优先搜索;

    本博客整理了当前经典的搜索算法的实现,并进行了简单的分析;博客中所有的代码实现位于:https://github.com/yaowenxu/codes/tree/master/搜索算法 ; 如果代码对您有帮助,希望能点击star~基于推荐和鼓励!感谢~

    基本概念: 

    • 搜索:就是在指定结构内,找到满足条件的关键字;这个结构可以是查找表结构,也可以是树结构也可以是图结构;
    • 查找表:带有相同种类键值的元素所构成的集合;
    • 关键字:元素中的某一项数字和标识,一个数据可以有很多关键字,可以通过多种维度来进行搜索;
    • 主键:可以用来唯一标识数据或者记录的关键字;
    • 静态查找表:查询某个特定的元素是否在表中;只做查找操作,查找过程中集合中的数据不发生变化;
    • 动态查找表:在查找过程中,同时进行插入或者删除数据;
    • 内查找:全部过程中都在内存中进行,为内查找;
    • 外查找:全部过程中需要访问外存,为外查找;
    • 性能评价:ASL(Average Search Length),平均比较长度;表示在查找过程中对关键字的需要执行的平均比较长度(平均比较次数),来进行评价算法性能优劣;
    • 查找算法选取:判断当前数据的组织结构,是线性表还是树结构还是图结构;如果是顺序表,还要考虑表格中的数据是否有序;

    顺序查找:顺序查找的思想是从左到右依次进行扫描比较,如果满足指定的查找条件则查找成功,若到末尾还未找到,则数组中无满足结构,适合与线性表;数据可以有序也可以无序;

    #define DEBUG 1
    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    void printarray(vector<int> &arr);
    
    void seqsearch(vector<int> &arr, int v=500){
        cout << "开始查找数据:" << v << endl;
        bool flag =  true;
        for (int i = 0; i < arr.size(); i++)
        {
            if(arr[i] == v){
                cout << "满足索引:" << i << endl;
                flag = false;
            }
        }
        if (flag)
        {
            cout << "无满足数据!" << endl;
        }
    }
    
    // 打印函数;
    void printarray(vector<int> &arr){
        for(int i = 0; i < arr.size(); i++){
            cout << arr[i] << " ";
        }
        cout << endl;
    }
    
    int main(){
        vector<int> arr; 
        freopen("in.txt", "r", stdin); // 重定向到输入 
        int i = 0; 
        int tmp; 
        while (cin >> tmp)
        {   
            arr.push_back(tmp);
            // cout << inarray[i] << endl;
            i++;
        }
        int num =  i;
        cout << "输入数据:" << endl;
        printarray(arr);
        cout << endl;
        if (DEBUG){
            cout << "查找过程:" << endl;
        }
    
        // 顺序查找
        seqsearch(arr);
        return 0;
    }
    顺序查找算法模板
    bash-3.2$ c++ 顺序查找.cc;./a.out
    输入数据:
    1 2 3 500 9 7 6 500 1 2 
    
    查找过程:
    开始查找数据:500
    满足索引:3
    满足索引:7
    查找算法输出样例
    算法复杂度:如果只查找一个元素,第一个元素满足情况为1;最后一个满足情况,需要比较n次;
    平均时间复杂度:ASL =  (n+...+1)/n = (n+1)/2,O(n);

    二分查找:二分查找又称为折半查找;思想是将查找的关键字与中间记录关键字进行比较,如果相等则查找结束;若不相等,比较自身和中间元素的大小,如果小于中间元素,则在左半部递归查找,如果大于中间元素则在右半部递归查找;该算法适合有序顺序表的查找;二分查找使用了一种减治的思想;

    #define DEBUG 1
    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    void printarray(vector<int> &arr);
    
    // 递归实现,找出其中一个满足的方案;如果需要找出所有的满足方案,只要先找出其中一个满足方案,然后在其左右顺序搜索就可以了;(因为数组是排序好的)
    void binsearch(vector<int> &arr, int start, int end, int v=900){
        if(DEBUG){
            cout << "s=" << start << " " << "e=" << end << endl;
        }
        if(end < start){
            cout << "无满足数据!" << endl;
            return;
        }
        int mid = (start+end)/2;
        if(arr[mid] == v){
            cout << "满足索引:" << mid << endl;
            return;
        }
        if(arr[mid] < v){
            binsearch(arr, mid+1, end);
        }
        if(arr[mid] > v){
            binsearch(arr, start, mid-1);
        }
    }
    
    // 非递归实现,非递归实现使用循环实现,注意循环的出口;以及索引的更新;
    void binsearch_2(vector<int> &arr, int v=900){
        int start =  0;
        int end = arr.size()-1;
        int flag = true;
        //使用 do-while 来进行循环
        do {
            int mid = (start+end)/2;
            if(DEBUG){
                cout << "s=" << start << " " << "e=" << end << endl;
            }
            if (arr[mid]==v){
                cout << "满足索引:" << mid << endl;
                flag = false;
                break;
            }
            if (arr[mid] > v){
                end = mid-1;
            }
            if (arr[mid] < v){
                start = mid+1;
            }
        } while (end >= start);
        if(flag){
            cout << "无满足数据!" << endl;
        }
    }
    
    // 打印函数;
    void printarray(vector<int> &arr){
        for(int i = 0; i < arr.size(); i++){
            cout << arr[i] << " ";
        }
        cout << endl;
    }
    
    int main(){
        vector<int> arr; 
        freopen("in.txt", "r", stdin); // 重定向到输入 
        int i = 0; 
        int tmp; 
        while (cin >> tmp)
        {   
            arr.push_back(tmp);
            // cout << inarray[i] << endl;
            i++;
        }
        int num =  i;
        sort(arr.begin(), arr.end());
        cout << "输入数据:" << endl;
        printarray(arr);
        cout << endl;
        if (DEBUG){
            cout << "查找过程:" << endl;
        }
    
        // 顺序查找
        cout << "binsearch-递归:" << endl;
        binsearch(arr, 0, arr.size()-1);
        cout << "binsearch-非递归:" << endl;
        binsearch_2(arr);
        return 0;
    }
    二分查找算法模板(递归与非递归实现)
    bash-3.2$ c++ 二分查找.cc; ./a.out
    输入数据:
    1 2 4 5 7 8 300 900 
    
    查找过程:
    binsearch-递归:
    s=0 e=7
    s=4 e=7
    s=6 e=7
    s=7 e=7
    满足索引:7
    binsearch-非递归:
    s=0 e=7
    s=4 e=7
    s=6 e=7
    s=7 e=7
    满足索引:7
    二分查找算法输出样例
    平均时间复杂度:查找区间可以看作,中间为树的根;左区间为左子树,右区间为右子树,整个查找过程中为二叉树;平均查找就是从二叉树的深度,为 O(logn);但一般数据使用二分查找,要求数据有序,如果数据无序,则先需要使用排序算法对无序数组进行排序;本实现使用的是 sort函数;当然你可以自行实现;

    分块查找:分块查找,分块就是把数据分为很多块;块内的数据是没有顺序的;块与块之间是有序的;左块中的元素小于右块中元素的最小值;分块查找由分块有序的线性表和有序的索引表构成;索引表记录了每个块的最大关键字和块的起始位置;在查找过程中,使用二分查找定位到对应的块;然后在块中进行顺序搜索;分块查找支持动态数据查找;

    #include <iostream>
    using namespace std;
    
    int seqtable[20] = {8, 14, 6, 9, 10, 22, 34, 18, 19, 31, 40, 38, 54, 66, 46, 71, 78, 68, 80, 85}; // 顺序表
    int indextable[4][2] = {{14, 0},{34, 5},{66, 10},{85, 15}}; // 索引表 
    
    void blocksearch1(int v = 85){
        // 二分查找;
        int start = 0;
        int stop = 3;
        // 顺序搜索的范围,该变量由二分搜索查表确定
        int s = 0;
        int e = 20;
        do{
            int mid =  (start+stop)/2;
            cout << "二分查找前:" << "start:" << start << " mid:" << mid << " stop:" << stop << " s=" << s << " e=" << e << endl;
            if(indextable[mid][0] < v){
                start = mid+1;
                if (mid == 3){
                    cout << "无满足数据!" << endl;
                    return;
                }
                s =  indextable[mid+1][1];
            }
            if(indextable[mid][0] >= v){
                stop = mid-1;
                if (mid < 3){
                    e =  indextable[mid+1][1];
                }
            }
            cout << "二分查找后:" << "start:" << start << " mid:" << mid << " stop:" << stop << " s=" << s << " e=" << e << endl;
        }while(stop >= start);
        
        // 顺序搜索
        cout << "顺序搜索区间: " << "s=" << s << " e=" << e << endl; 
        int flag = true;
        for (int i = s; i < e; i++){
            if(seqtable[i] ==  v){
                cout << "满足索引:" << i << endl;
                flag = false;
                break;
            }
        }
        if (flag){
            cout << "无满足数据!" << endl;
        }
    }
    
    void blocksearch2(int v = 85){
        // 二分查找;
        int start = 0;
        int stop = 3;
        // 顺序搜索的范围,该变量由二分搜索查表确定
        int s = 0;
        int e = 20;
        do{
            int mid =  (start+stop)/2;
            cout << "二分查找前:" << "start:" << start << " mid:" << mid << " stop:" << stop << " s=" << s << " e=" << e << endl;
            if(indextable[mid][0] == v){  // 加入此判断,可以过早终止;
                s = indextable[mid][1];
                if (mid < 3){
                    e =  indextable[mid+1][1];
                }
                break;
            }
            if(indextable[mid][0] < v){   // 加入此判断可以过早终止;
                start = mid+1;
                if (mid == 3){
                    cout << "无满足数据!" << endl;
                    return;
                }
                s =  indextable[mid+1][1];
            }
            if(indextable[mid][0] > v){
                stop = mid-1;
                if (mid < 3){
                    e =  indextable[mid+1][1];
                }
            }
            cout << "二分查找后:" << "start:" << start << " mid:" << mid << " stop:" << stop << " s=" << s << " e=" << e << endl;
        }while(stop >= start);
        
        // 顺序搜索
        cout << "顺序搜索区间: " << "s=" << s << " e=" << e << endl; 
        int flag = true;
        for (int i = s; i < e; i++){
            if(seqtable[i] ==  v){
                cout << "满足索引:" << i << endl;
                flag = false;
                break;
            }
        }
        if (flag){
            cout << "无满足数据!" << endl;
        }
    }
    
    int main(){
        cout << "分块查找1:" << endl;
        blocksearch1();
        cout << endl;
        cout << "分块查找2:" << endl;
        blocksearch2();
    }
    分块查找算法实现模板
    bash-3.2$ c++ 分块查找.cc; ./a.out
    分块查找1:
    二分查找前:start:0 mid:1 stop:3 s=0 e=20
    二分查找后:start:2 mid:1 stop:3 s=10 e=20
    二分查找前:start:2 mid:2 stop:3 s=10 e=20
    二分查找后:start:3 mid:2 stop:3 s=15 e=20
    二分查找前:start:3 mid:3 stop:3 s=15 e=20
    二分查找后:start:3 mid:3 stop:2 s=15 e=20
    顺序搜索区间: s=15 e=20
    满足索引:19
    
    分块查找2:
    二分查找前:start:0 mid:1 stop:3 s=0 e=20
    二分查找后:start:2 mid:1 stop:3 s=10 e=20
    二分查找前:start:2 mid:2 stop:3 s=10 e=20
    二分查找后:start:3 mid:2 stop:3 s=15 e=20
    二分查找前:start:3 mid:3 stop:3 s=15 e=20
    顺序搜索区间: s=15 e=20
    满足索引:19
    分块查找算法输出样例
    算法时间复杂度:块间使用二分查找进行查找;块内使用顺序搜索进行查找;效率介于顺序查找和二分查找之间;
    平均查找长度:二分查找 > 分块查找 > 顺序查找;
    适用性:顺序搜索无条件限制,二分查找要求数据有序;分块查找要求分块有序;
    存储结构:顺序查找和分块查找适用于顺序表和链表;二分查找适用于顺序表;
    分块查找优点:分块查找效率介于顺序查找和二分查找之间,可以用于动态数据查找;

    广度优先搜索(BFS):Breadth First Search; 从树的根开始,从上打下,从左到右遍历树的节点;

    深度优先搜索(DFS): Depth First Search; 沿着树的深度优先遍历树的节点,直到到达叶子节点,再进行回溯;根绝根节点遍历顺序的不同,又分为先序,中序和后序遍历;

    关于深度优先搜索和广度优先搜索,在经典数据结构实现与分析树结构部分进行详细讲解;

    保持更新,转载请注明出处;更多内容请关注cnblogs.com/xuyaowen;

    参考链接:

    七大查找算法(Python)

    几种常见的搜索算法 

    程序员的内功——数据结构和算法系列 

    排序与搜索 

  • 相关阅读:
    【摄影】EOS 6D通过WIFI连接手机
    【Teradata SQL】dayofyear与td_day_of_year函数区别
    【PS技巧】如何修人物的脸型
    【Teradata数据保护机制】锁
    【数据库】SQL标准定义的四个事务隔离级别
    【TD函数】Teradata正则表达式函数
    Teradata复杂视图跨库访问权限问题
    CPU芯片组与总线
    单核CPU、多个CPU(路)、超线程技术、多核CPU(物理核、逻辑核)
    Idea删除当前类所有的注释
  • 原文地址:https://www.cnblogs.com/xuyaowen/p/search-algos.html
Copyright © 2011-2022 走看看