zoukankan      html  css  js  c++  java
  • 查找算法--线性结构的查找方法

    查找基本概念:

       查找又称为检索,指从一批记录中找出满足指定条件的某一记录过程。在日常生活中比如通讯录查找,字典查找等经常使用查找方法;在程序设计中,查找在许多程序中需要占用很多时间,因此,一个好的查找方法可以提高程序的运行速度。

       主关键字和次关键字:

        在需要查找的数据结构中,每条记录一般包含多个数据域。查找条件一般是给定其中的一个或几个域的值,这些作为查找条件的域成为关键字(KEY),如果关键字可以唯一标示数据结构中的一条记录,则称此关键字(Primary Key);若关键字不能唯一区别各个不同的记录,则称此关键字为次关键字(Secondary Key)。最常用,最主要的是以主关键字查找

      查找结果

       如果通过查找找到与给定关键字相对应的记录,表明查找成功,返回记录的存储位置,以便对记录进行处理(输出,修改,删除等)。找不到与给定关键字对应的记录,表示查找失败,返回一个特定的失败值。

      静态查找表和动态查找表

    进行查找使用的数据结构称为查找表,可以分为静态查找表和动态查找表:

       静态查找表:查找过程中,数据结构不改变的查找称为静态查找表,在静态查找表中,查找失败后,将返回失败值。

       动态查找表:查找过程中,数据结构随查找过程进行改变的查找表称为动态查找表,在动态查找表中,查找失败后,将查找表中原来不存在的记录增加到查找表中,另外,动态查找表可以删除指定的关键字的记录。

    下面介绍当数据的结构为线性结构时,采用的两种简单的查找方法:顺序查找折半查找(又叫二分查找)

    1.顺序查找:

    顺序查找(Sequential Search)是最简单的一种查找方法,基本思想是:从线性表一端开始,依次将每个记录的关键字与给定值比较,若关键字等于给定值,表示查找成功,返回记录序号,若将线性表中所有记录都比较完,没有找到关键字和给定值相等的记录,查找失败,返回失败值。

    例:

    #include <stdio.h>
    #define ARRAYLEN 8   //静态查找表的元素 
    int source[ARRAYLEN]={69,65,90,37,92,6,28,54};   //静态查找表 
    int SeqSearch(int s[],int n,int key)
    {
        int i;
        for(i=0;i<n&&s[i]!=key;i++)   //循环查找关键字 
          ;          
        if(i<n)   //在静态查找表中找到关键字 
          return i;
        else 
          return -1;
    }
    int main()
    {
        int key,i,pos;
        printf("
    请输入关键字:");
        scanf("%d",&key);
        pos=SeqSearch(source,ARRAYLEN,key); 
        printf("原数据:
    ");
        for(i=0;i<ARRAYLEN;i++)
          printf("%d  ",source[i]);  
        if(pos>=0)
          printf("
    查找成功,该关键字位于%d个位置:",pos+1); //加1让位置显示从1开始 
        else
          printf("
    查找失败!");
        return 0;
    }

        在上面顺序查找的循环语句中,每次循环都需要进行两个比较(i<n && r[i]!=key),如果静态查找表中的数据很多,每两次比较需要进行较长时间,这样程序效率比较低,这时可以对SeqSearch算法进行改进,在创建静态查找表中,需要在该表的末端增加一个空的单元,用来保存查找的关键字,这样确保静态查找表中有一个和查找关键字相同的数据,可以去除i<n的判断,每次查找时,查找表中总是能找到关键字,但是若找到第n+1个元素才找到关键字时才找到关键值,表示查找失败。

    改进后:

    #include <stdio.h>
    #define ARRAYLEN 8   //静态查找表的元素 
    int source[ARRAYLEN+1]={69,65,90,37,92,6,28,54};   //静态查找表 
    int SeqSearch(int s[],int n,int key)
    {
        int i;
        for(i=0;s[i]!=key;i++)   //循环查找关键字 
          ;          
        if(i<n)   //在静态查找表中找到关键字 
          return i;
        else 
          return -1;
    }
    int main()
    {
        int key,i,pos;
        printf("
    请输入关键字:");
        scanf("%d",&key);
        source[ARRAYLEN]=key;    //将key保存到查找表最后 
        pos=SeqSearch(source,ARRAYLEN,key); 
        printf("原数据:
    ");
        for(i=0;i<ARRAYLEN;i++)
          printf("%d  ",source[i]);  
        if(pos>=0)
          printf("
    查找成功,该关键字位于%d的位置:",pos+1); //加1让位置显示从1开始 
        else
          printf("查找失败
    ");
        return 0;
    }

    上述代码第22行将key保存到查找表的最后,key值一个一个与查找表中元素对比,当在第9个元素之前对比成功,则查找成功,当找到第9个位置即key保存的位置,肯定能匹配成功,但是此时是第9个了,表示查找失败。此过程省去了i<n的比较。

        顺序查找优点:对静态查找表中的数据的顺序没有要求,当需要创建动态查找表时,可以方便的将查找不成功的数据添加到查找表的末尾。

        顺序查找表的缺点:速度慢,在最坏情况下,查找成功需要进行n此比较,查找失败要n+1此比较。

    2.折半查找:

        折半查找又叫二分查找,这种查找方法要求查找表中数据是线性结构保存,而且查找表中数据是按照关键字有序排列的(从小到大或从大到小)

       下面以数据从小到大的n个元素有序排列介绍折半查找过程:

       首先是位于查找表中间的位置元素的序号m(m=n/2),取s[m]的关键字与给定值key进行比较,有三种可能:

    1.  若s[m]=key,表示查找成功。
    2. 若s[m]>key,表示关键字key在最小值与中间值之间,在前半部分进行折半查找。
    3. 若s[m]<key,表示关键字key在最大值与中间值之间,在后半部分进行折半查找。

        从上面过程看出,折半查找是一种递归的过程,每次折半,都能使查找的范围缩小一半,当查找的范围缩小到只剩下一个元素时,而该元素与关键字不相等,表示查找失败。

        在最坏情况下,折半查找所需要的比较次数是O(logn),查找效率比顺序查找快很多。

       比如有这几个数据:6,12,28,37,54,65,69,83,90,92,以37作为关键字,进行查找:

     过程:

    折半查找过程

    下面编写程序实现折半查找的过程:

    #include<stdio.h>
    #define ARRAYLEN 10
    int source[]={6,12,28,37,54,65,69,83,90,92};
    int BinarySearch(int s[],int n,int key)
    {
        int low,height,mid;
        low=0;
        height=n-1;
        while(low<=height)      //查找范围 至少包含一个元素
        {
            mid=(low+height)/2;   
            if(s[mid]==key)
              return mid;     //返回序号
             else if(s[mid]>key)
               height=mid-1;
              else
                 low=mid+1;    //定义查找范围 
        } 
        return -1;   //返回查找失败 
    }
    int main()
    {
        int key,i,pos;
        
        printf("
    请输入要查找的关键字:
    ");
        scanf("%d",&key);
        pos=BinarySearch(source,ARRAYLEN,key); 
        printf("原数据:");
        for(i=0;i<ARRAYLEN;i++)
          printf("%d  ",source[i]);
        printf("
    ");
        if(pos>=0)
          printf("
    查找成功,该关键字位于第%d个位置。
    ",pos+1);
        else
          printf("查找失败
    ");
        return 0;
    }

    折半查找的优点是:平均性能好,查找速度快,最多查找次数为O(log(n)),可以快速逼近关键字。

    折半查找的缺点是:对查找表中数据排列有要求,首先是顺序排列,而且是有序排列的(从小到大或从大到小),因此使用折半查找时需要先对查找表进行排序;当查找关键字不成功时,如果需要将该关键字添加到查找表中,则需要对已有数据进行大量移动,同样删除也需要移动大量数据。

     

  • 相关阅读:
    Entity Framework 5.0运行.NET Framework 4.0之上在查询表达式中使用显示转换的一个问题
    How to get memcached all keys
    不同dll相同Type.FullName引发的问题
    WinDbg的cmdtree命令
    警惕缺省参数(Optional Parameters)对类型(Type)构造函数(Constructor)设计的影响
    如何解决Silverlight InitializeError #2103 Invalid or malformed application: Check manifest
    在北京拿5000.00元的工资
    分区表2
    C#操作config文件
    分区表1
  • 原文地址:https://www.cnblogs.com/guihailiuli/p/4160621.html
Copyright © 2011-2022 走看看