精华内容
下载资源
问答
  • 顺序查找

    千次阅读 2021-05-27 17:35:26
    顺序查找通常分为对一般的无序线性表的顺序查找和对按关键字有序的顺序表的顺序查找。下面分别进行讨论。 1.一般线性表的顺序查找 作为种最直观的查找方法, 其基本思想是从线性表的一端开始,逐个检 查关键字是否...

    顺序查找的算法思想

    顺序查找又称线性查找,主要用于在线性表中进行查找。顺序查找通常分为对一般的无序线性表的顺序查找和对按关键字有序的顺序表的顺序查找。
    在这里插入图片描述

    顺序查找的实现

    作为一种最直观的查找方法, 其基本思想是从线性表的一端开始,逐个检查关键字是否满足给定的条件。若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;若已经查找到表的另一端,但还没有查找到符合给定条件的元素,则返回查找失败的信息。
    在这里插入图片描述

    typedef struct //查找表的数据结构
    {
        ElemType *elem; //动态数组基址,建表时按实际长度分配,0号单元留空
        Int TableLen; //表的长度
    }SSTable;
    //顺序查找
    int Search_Seq(SSTable ST, ElemType key)
    {
    //在顺序表ST中顺序查找关键字为key的元素。若找到则返回该元素在表中的位置
        for(i=ST.TableLen; ST.elem[i]!=key; --i); //从后往前找
        return i; //若表中不存在关键字为key的元素,将查找到i为0时退出for循环
    }
    

    顺序查找的实现(哨兵)

    下面给出其算法,主要是为了说明其中引入的"哨兵"的作用。
    在这里插入图片描述

    typedef struct //查找表的数据结构(顺序表)
    {
        ElemType *elem; //动态数组基址,建表时按实际长度分配,0号单元留空
        Int TableLen; //表的长度
    }SSTable;
    //顺序查找
    int Search_Seq(SSTable ST, ElemType key)
    {
    //在顺序表ST中顺序查找关键字为key的元素。若找到则返回该元素在表中的位置
        ST.elem[0]=key; //哨兵
        int i;
        for(i=ST.TableLen; ST.elem[i]!=key; --i); //从后往前找
        return i; //若表中不存在关键字为key的元素,将查找到i为0时退出for循环
    }
    

    上述算法中,将ST.elem[0]称为"哨兵"。引入它的目的是使得Search_Seq内的循环不必判断数组是否会越界,因为满足i==0时,循环一定会跳出。需要说明的是,在程序中引入"哨兵"并不是这个算法独有的。引入"哨兵"可以避免很多不必要的判断语句,从而提高程序效果。

    查找效率分析

    对于有n个元素的表,给定值key与表中第i个元素的关键字相等,即定位第i个元素时,需进行n-i+1次关键字的比较,即Ci=n-i+1。查找成功时,顺序查找的平均长度为
    ASL成功=∑Pi(n-i+1)

    当每个元素的查找概率相等, 即Pi= 1/n时,有
    ASL成功=∑Pi(n-i+1)=(n+1)/2

    查找不成功时,与表中各关键字的比较次数显然是n + 1次,从而顺序查找不成功的平均查找长度为ASL不成功=n+ 1。
    在这里插入图片描述
    通常,查找表中记录的查找概率并不相等。若能预先得知每个记录的查找概率,则应先对记录的查找概率进行排序,使表中记录按查找概率由小至大重新排列。

    综上所述,顺序查找的缺点是当n较大时,平均查找长度较大,效率低;优点是对数据元素的存储没有要求,顺序存储或链式存储皆可。对表中记录的有序性也没有要求,无论记录是否按关键码有序,均可应用。同时还需注意,对线性的链表只能进行顺序查找。

    顺序查找的优化(对有序表)

    若在查找之前就已经知道表是关键字有序的,则查找失败时可以不用再比较到表的另一端就能返回查找失败的信息,从而降低顺序查找失败的平均查找长度。

    假设表L是按关键字从小到大排列的,查找的顺序是从前往后,待查找元素的关键字为key,当查找到第i个元素时,发现第i个元素对应的关键字小于key,但第i+ 1个元素对应的关键字大于key,这时就可返回查找失败的信息,因为第i个元素之后的元素的关键字均大于key,所以表中不存在关键字为key的元素。
    在这里插入图片描述
    在有序表的顺序查找中,查找成功的平均查找长度和一般线性表的顺序查找一样。查找失败时,查找指针一定走到了某个失败结点。这些失败结点是我们虚构的空结点,实际上是不存在的,所以到达失败结点时所查找的长度等于它上面的一个圆形结点的所在层数。查找不成功的平均查找长度在相等查找概率的情形下为
    ASL不成功=∑qj(lj-1)=(1+2+…+n+n)/(n+1)=n/2+n/(n+1)

    式中,qj是到达第j个失败阶段的概率,在相等查找概率的情形下,它为1/(n+1);lj是第j个失败结点所在的层数。当n=6时,ASL不成功=6/2+6/7=3.86,比一般的顺序查找算法好一些。

    用查找判定树分析ASL

    可以用如图所示的判定树来描述有序顺序表的查找过程。树中的圆形结点表示有序顺序表中存在的元素;树中的矩形结点称为失败结点(注意,若有n个查找成功结点,则必定相应地有n+1个查找失败结点),它描述的是那些不在表中的数据值的集合。若查找到失败结点,则说明查找不成功。
    在这里插入图片描述

    顺序查找的优化(被查概率不相等)

    在这里插入图片描述
    注意,有序表的顺序查找和后面的折半查找的思想不一样的,且有序表的顺序查找中的线性表可以是链式存储结构。
    在这里插入图片描述

    展开全文
  • 文章目录查找查找的概念顺序查找顺序查找-算法原理顺序查找-算法实现顺序查找-性能分析折半查找折半查找-算法原理折半查找-算法实现折半查找-性能分析分块查找分块查找-算法原理分块查找-算法实现分块查找-性能分析 ...

    查找

    ​ 查找是在查询数据过程中必不可少的一个环节,那么如何来进行查找,以及如何进行高效率的查找,就是接下来要解决的问题。

    查找的概念

    ​ 首先提出一些定义,在查找元素的时候,必然是从一堆数据中去找自己想要的数据,那么这种由同一类型的数据元素构成的集合就被称为查找表。对于查找表可执行以下操作:

    1. 查询某个“特定的”数据元素是否在查找表中;
    2. 检索某个“特定的”数据元素的各种属性;
    3. 在查找表中插入一个数据元素;
    4. 从查找表中删去某个数据元素

    根据查找表的操作方式来分类,可以将查找表分为两类:静态查找表和动态查找表。

    1. 静态查找表:仅作查询和检索的查找表。
    2. 动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已存在的某个数据元素

    在数据表中,应该用一个东西来标识每一个数据元素用以识别该数据,这个东西就叫做关键字,关键字是数据元素(或记录)中某个数据项的值,用以标识(识别)一个数据元素(或记录)。其中关键字也可以进行细分:

    1. 主关键字:可以识别唯一的一个记录的关键字
    2. 次关键字:能识别若干记录的关键字

    关于关键字这里可以简单举个例子,以全校成绩为例,学号就是每个学生的主关键字,因为一个学号唯一识别一个学生,学院就是次关键字,学院可以识别若干个学生,但是不能唯一识别一个学生。

    ​ 那么查找是一个什么过程呢,查找就是根据给定的值,在查找表中确定一个其关键字等于给定值的数据元素那么根据查询结果来看分为查询成功和查询不成功,查找成功就是在查找表中查找到指定的记录;查找不成功就是在查找表中没有找到指定记录。

    ​ 最后还有很关键的一点,就是如何衡量一个查找算法的效率。这里主要参考以下几点:

    1. 时间复杂度
    2. 空间复杂度
    3. 平均查找长度 A S L ASL ASL

    这里重点讲一下什么是平均查找长度 A S L ASL ASL,平定义为确定记录在表中的位置所进行的和关键字比较的次数的平均值,可以使用下面的公式来表示。
    A S L = ∑ i = 1 n P i C i ASL=\sum_{i=1}^n{P_iC_i} ASL=i=1nPiCi
    其中, n n n为查找表的长度,即表中所含元素。 P i P_i Pi为查找第 i i i哥元素的概率( ∑ P i = 1 \sum{P_i=1} Pi=1)。 C i C_i Ci是查找第 i i i个元素时同给定值 K K K比较的次数。

    顺序查找

    ​ 顺序查找算法是查找算法中最简单直接的一种方法,它是属于静态查找表中的一种查找方法。

    顺序查找-算法原理

    ​ 顺序查找有两种实现方式,第一种就是平时常用的那种,从数组的第一个元素开始往后遍历,直到遍历到数组的最后一个元素或者说找到对应的元素才停止。

    ​ 对于第一种方式,在查找的时候还需要考虑数组是否会越界的问题,那么为了解决这个问题,就采用哨兵的方式来进行查找。一般情况将数组的第一个元素当作哨兵,放置待查询关键字,然后从数组的最后一个元素开始往前查找,这样一来就不用考虑越界的情况,因为数组的第一个元素一定会等于最后一个元素。
    在这里插入图片描述

    在这里插入图片描述

    顺序查找-算法实现

    ​ 对于第一种方法,直接采用最简单的 f o r for for循环从第一个遍历到最后一个即可,代码如下所示。

    // 顺序查找,不带哨兵
    int Sequential_Search(int data[], int n, int key)
    {
    	// 通过for循环查找即可
    	for (int i = 1; i <= n; i++)
    	{
    		// 如果相等则返回下标
    		if (data[i] == key)
    			return i;
    	}
    	// 没有找到返回0
    	return 0;
    }
    

    ​ 对于第二种哨兵法,整体思路和前面相同,都是通过遍历的方法来进行查找,但是减少了数组越界的判断。

    // 顺序查找,带哨兵
    int Sequential_Search2(int data[], int n, int key)
    {
    	data[0] = key;	// 第一个位置当作哨兵
    	int index = n;	// 从后往前进行查找
    	// 此处省略对数组越界的判断,因为data[0] = key
    	while (data[index] != key)
    	{
    		index--;
    	}
    	return index;
    }
    

    顺序查找-性能分析

    ​ 对于顺序表而言, C i = n − i + 1 C_i=n-i+1 Ci=ni+1,同时假设是等概率查找,即 P i = 1 n P_i=\frac{1}{n} Pi=n1,故可以计算得到该顺序表的平均查找长度为
    A S L = n P 1 + . . . + P n = n ( n + 1 ) 2 ASL=nP_1+...+P_n=\frac{n\left( n+1 \right)}{2} ASL=nP1+...+Pn=2n(n+1)
    ​ 同时顺序查找的优点在于其简单且适应面广(对表没有额外要求),但是缺点也很明显,平均查找长度较大,尤其是当 n n n很大时,查找效率很低。

    折半查找

    ​ 在平常查找过程中,例如在图书馆找某本书,如果图书馆中的书已经按照书名的首字母拼写摆放好了,那么就可以根据这些顺序来更加快速的找到想要的书籍,而折半查找就是源于这一思想,同时折半查找也是静态查找表中的查找方法。

    折半查找-算法原理

    ​ 首先需要声明的是,折半查找算法是有序表的查找方法,这也就代表在折半查找算法中,静态查找表按关键字大小的次序,有序地存放在顺序表中。

    ​ 在有序表中,可以通过不断缩小区间的方法来确定要查找的元素的位置,原理类似于数学中的牛顿二分法。每次查找时根据区间的上下界,计算出一个中点值,该中点值的关键字如果大于查找的关键字,则取后半部分区间继续查找,反之则取前半部分区间继续查找,直到找到该记录或区间无法再缩小为止(找不到)。

    ​ 接下来查看一个查找成功的例子。
    在这里插入图片描述

    ​ 以及一个查找不成功的例子。
    在这里插入图片描述

    折半查找-算法实现

    ​ 具体到代码实现时,只需要将上述步骤设计成流程即可,如下所示。

    1. n n n个对象从小到大存放在有序顺序表 S T ST ST中, k k k为给定值
    2. l o w low low h i g h high high指向待查元素所在区间的下界、上界,即 l o w = 1 , h i g h = n low=1, high=n low=1,high=n
    3. m i d mid mid指向待区间的中点,即 m i d = ( l o w + h i g h ) / 2 mid=(low+high)/2 mid=(low+high)/2
    4. k k k m i d mid mid指向的记录比较
      k = S T [ m i d ] . k e y k=ST[mid].key k=ST[mid].key,查找成功
      k < S T [ m i d ] . k e y k<ST[mid].key k<ST[mid].key,则 h i g h = m i d − 1 high=mid-1 high=mid1 [上半区间]
      k > S T [ m i d ] . k e y k>ST[mid].key k>ST[mid].key,则 l o w = m i d + 1 low=mid+1 low=mid+1 [下半区间]
    5. 重复3,4操作,直至low>high时,查找失败。
    // 折半查找
    int Binary_Search(int data[], int n, int key)
    {
    	int low = 1;	// 低位
    	int high = n;	// 高位
    	while (low <= high)	// 不断缩小区间
    	{
    		int mid = (low + high) / 2;	// 中值
    		if (data[mid] > key)	// 如果中值大于关键字,则下一次从[low, mid-1]中找
    			high = mid - 1;
    		else if (data[mid] < key)	// 如果中值小于关键字,则下一次从[mid+1,high]中找
    			low = mid + 1;
    		else	// 成功找到则直接返回
    			return mid;
    	}
    	// 没有找到返回0
    	return 0;
    }
    

    折半查找-性能分析

    ​ 在分析折半查找的平均查找长度时,需要借助到二叉树来进行分析,由于每次都是折半的过程,那么就可以将原来的有序序列看做成一个二叉树(中序遍历为有序结果),如下所示。
    在这里插入图片描述

    ​ 在具体到查找时,也是按照上述顺序逐层进行查找,因为有 n n n个结点的上述二叉树深度为 [ log ⁡ 2 n ] + 1 [\log _{2}^{n}]+1 [log2n]+1,故折半查找法在查找过程中比较次数不超过 [ log ⁡ 2 n ] + 1 [\log _{2}^{n}]+1 [log2n]+1次。上述二叉树也被称为判定树。

    ​ 设有序表的长度 n = 2 h − 1 n=2^h-1 n=2h1,则描述折半查找的判定树是深度为 h h h的满二叉树。树中层次为1的结点有1个,层次为 h h h的结点有 2 h − 1 2^{h-1} 2h1个。

    ​ 假设表中每个记录的查找概率相等,则查找成功时折半查找的平均查找长度为
    A S L = 1 n ∑ i = 1 n C i = 1 n [ ∑ j = 1 h j ⋅ 2 j − 1 ] = n + 1 n ASL=\frac{1}{n}\sum_{i=1}^n{C_i=}\frac{1}{n}\left[ \sum_{j=1}^h{j\cdot 2^{j-1}} \right] =\frac{n+1}{n} ASL=n1i=1nCi=n1[j=1hj2j1]=nn+1
    ​ 折半查找的优点在于相比于顺序查找,其查找效率很高,特别是在静态查找表的长度很长时,但是缺点也很明显,那就是只能适用于有序表,且数据需要以顺序存储结构存储。

    分块查找

    ​ 分块查找是一种索引顺序表查找方法,是折半查找和顺序查找的简单结合。索引顺序表是将整个表分成几块,块内无序,块间有序,这两个要求的含义具体如下所示。

    1. 块内无序:同一块内的记录不要求有序。
    2. 块间有序:后一块中所有记录的关键字均大于前一块中所有记录的最大关键字。

    分块查找-算法原理

    ​ 那么对于索引顺序表(分块有序表)可以将其分为两个表,第一个表就是主表,用数组存放待查记录,每个数据元素至少含有关键字域;第二个就是索引表,每个结点含有最大关键字域和只想本快第一个结点的指针,如下所示。
    在这里插入图片描述

    ​ 那么在查找某个元素时,首先通过折半查找的方法来索引块中找到该元素所属的块,之后再通过顺序查找的方式在该块中找到对应的元素。
    在这里插入图片描述

    分块查找-算法实现

    ​ 分块查找主要就是折半查找和顺序查找的合并版,实现起来没有问题,重点在于如何建立索引表。这里的前提是已经分好了块,但是需要去标注每个块的起始下标,直接通过遍历主表元素即可,从第一个块的最大元素比较起,遇到的第一个比第一个块最大元素还大的元素,就是第二个块的起始元素,以此类推。

    // 创建索引表
    void Create_Index(int data[], int n, int index[], int indexOrder[])
    {
    	/// <summary>
    	/// 创建索引表
    	/// </summary>
    	/// <param name="data">查找表</param>
    	/// <param name="n">查找表长度</param>
    	/// <param name="index">每个块的最大数据</param>
    	/// <param name="indexOrder">每个块的起始下标</param>
    
    	int pos = 1;	// 数据从1开始
    	indexOrder[pos++] = 1;	// 第一组起点为1
    	for (int i = 1; i <= n; i++)	// 遍历所有数据
    	{
    		if (data[i] > index[pos - 1])	// 遇到第一个比前一个块最大数据大的
    		{
    			indexOrder[pos++] = i;	// 说明该点是一个新块的起点
    		}
    	}
    }
    

    ​ 这里为了简单起见,块的查找和块内查找都是使用了顺序查找进行实现,代码如下所示。

    // 分块索引查找
    int Index_Search(int data[], int n, int index[], int k, int indexOrder[], int key)
    {
    	/// <summary>
    	/// 分块索引查找
    	/// </summary>
    	/// <param name="data">查找表</param>
    	/// <param name="n">查找表长度</param>
    	/// <param name="index">每个块的最大数据</param>
    	/// <param name="k">块的个数</param>
    	/// <param name="indexOrder">每个块的起始下标</param>
    	/// <param name="key">待查找的关键字</param>
    	/// <returns></returns>
    
    	// 先找数据所属的块
    	int part = 1;	// 从第一块开始查找
    	int begin = 0;	// 数据所属块的起始下标
    	for (int i = 1; i <= k; i++)	// 逐块查找
    	{
    		// 如果当前块最大数据大于带查找关键字
    		// 则说明关键字就在该块中
    		if (index[i] >= key)	
    		{
    			part = i;
    			begin = indexOrder[i];
    			break;
    		}
    	}
    	int end = n;	// 初始化块的尾地址
    	if (part < k)	// 判断是否是最后一个块
    		end = indexOrder[part + 1] - 1;
    
    	// 顺序查找
    	for (int i = begin; i <= end; i++)
    	{
    		if (data[i] == key)
    			return i;
    	}
    	return 0;
    }
    

    分块查找-性能分析

    ​ 对于分块查找,设若将长度为 n n n的表分成 b b b块,每块含 s s s个记录,并设表中每个记录查找概率相等。

    ​ 用折半查找方法在索引表中查找索引块
    A S L 块间 ≈ l o g 2 n s + 1 ASL_{\text{块间}}\approx log_{2}^{\frac{\mathrm{n}}{\mathrm{s}+1}} ASL块间log2s+1n

    ​ 用顺序查找方法在主表对应块中查找记录
    A S L 块内 ≈ s 2 ASL_{\text{块内}}\approx \frac{\mathrm{s}}{2} ASL块内2s
    ​ 故总的平均查找长度为
    A S L ≈ l o g 2 n s + 1 + s 2 ASL\approx log_{2}^{\frac{\mathrm{n}}{\mathrm{s}+1}}+\frac{\mathrm{s}}{2} ASLlog2s+1n+2s

    展开全文
  • 顺序查找(SequentialSearch)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;...

    顺序查找( Sequential Search ) 又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到后一个(或第一个)记录,其关键字和给定信比较都不等时,则表中没有新金录,査找不成功。
     

     1.数组实现

    #include<stdio.h>
    #include<stdlib.h>
    typedef int KeyType;
    typedef char InfoType; 
    typedef struct
    {
    	KeyType key;
    	InfoType info;
    }Key;
    void Search_Seq01(Key *K, KeyType key, int len)//顺序查找
    {
    	int i;
    	for(i = 1; i < len; i++)
    		if(K[i].key == key)
    		{
    			printf("关键字信息为:%c\n", K[i].info);
    			break;
    		}
    }
    void Search_Seq02(Key *K, KeyType key, int len)//设置监视哨查找
    {
    	int i;
    	K[0].key = key;
    	for(i = len; K[i].key != key; i--);
    	printf("关键字信息为:%c\n", K[i].info);
    }
    
    int main()
    {
    	Key *K;
    	int i, M;
    	printf("请输入关键字数:");
    	scanf("%d", &M);
    	K = (Key *)malloc((M+1) * sizeof(Key));
    
    	//测试用例:1 a 2 b 3 c 4 d 5 e 6 f 7 g 8 h 9 i 10 j
    	printf("请输入关键字及关键字信息:\n");
    	for(i = 1; i <= M; i++)
    		scanf("%d %c", &K[i].key, &K[i].info);
    	
    	printf("顺序查找\nkey = 4\n");
    	Search_Seq01(K, 4, M);
    	printf("\n");
    
    	printf("设置监视哨顺序查找\nkey = 5\n");
    	Search_Seq02(K, 5, M);
    	printf("\n");
    
    	return 0;
    }
    

    2.顺序表实现

    #include<stdio.h>
    #include<stdlib.h>
    #define MAX 20
    typedef int KeyType;
    typedef char InfoType;
    
    typedef struct
    {
    	KeyType key;
    	InfoType info;
    }ElemType;
    
    typedef struct
    {
    	ElemType *R;
    	int length;
    }List,*SqList;
    
    void InitList(SqList *L)
    {
    	(*L) = (List *)malloc(sizeof(List));//给顺序表分配空间
    	(*L)->R = (ElemType *)malloc(MAX * sizeof(ElemType));//给数据域分配空间
    	(*L)->length = 0;
    }
    
    void CreateList(SqList *L)
    {
    	int i;
    	for(i = 1; i <= 10; i++)
    	{
    		(*L)->R[i].key = i;//赋值
    		(*L)->R[i].info = 'a'+i-1;//赋值
    		(*L)->length++;
    	}
    }
    
    
    void DispList(SqList L)
    {
    	int i;
    	for(i = 1; i <= L->length; i++)//关键字遍历
    		printf("%d ", L->R[i].key);
    
    	printf("\n");
    
    	for(i= 1; i <= L->length; i++)//关键字信息遍历
    		printf("%c ",L->R[i].info);
    
    	printf("\n\n");
    }
    
    int Search_Seq01(SqList L, KeyType key)//顺序查找
    {
    	int i;
    	for(i = 1; i <= L->length; i++)//判断语句一
    		if(L->R[i].key == key)//判断语句二
    			return i;
    	return 0;			
    }
    
    int Search_Seq02(SqList L, KeyType key)//设置监视哨顺序查找
    {
    	int i;
    	L->R[0].key = key;	//占用第一个数组位置做监视哨
    	for(i = L->length -1; L->R[i].key != key; i--);
    	//相比普通顺序查找,少了一个判断条件
    	//也就相当于快了将近一半的时间
    	return i;
    }
    
    int main()
    {
    	int m, n;
    	SqList L;
    	InitList(&L);
    	CreateList(&L);
    	printf("顺序表创建完成!\n");
    	printf("顺序表表长 = %d\n", L->length);
    	
    	printf("关键字信息遍历:\n");
    	DispList(L);
    
    	m = Search_Seq01(L, 4);
    	printf("顺序查找关键字key = 4\n");
    	printf("关键字位置:%d\n", m);
    	printf("关键字信息:%c\n\n", L->R[m].info);
    	
    	n = Search_Seq02(L, 5);
    	printf("监视哨顺序查找关键字key = 5\n");
    	printf("关键字位置:%d\n", n);
    	printf("关键字信息:%c\n", L->R[n].info);
    	return 0;
    }
    

     3.单链表实现

    #include<stdio.h>
    #include<stdlib.h>
    typedef int KeyType;
    typedef char InfoType;
    typedef struct LNode
    {
    	KeyType Key;
    	InfoType info;
    	struct LNode *next;
    }LNode, *LinkList;
    //初始化单链表
    void InitList(LinkList *L)
    {
    	(*L) = (LNode *)malloc(sizeof(LNode));
    	(*L)->next = NULL;
    	printf("单链表已初始化!\n");
    }
    //创建单链表
    void CreateList(LinkList *L)
    {
    	int i;
    	LinkList p = *L;
    	for(i = 1; i <= 10; i++)
    	{
    		LNode *s;//定义一个新结点
    		s = (LNode *)malloc(sizeof(LNode));//为结点分配空间
    		//给结点赋值关键字及信息
    		s->Key = i;
    		s->info = 'a'+i-1;
    		//将新结点依次接入单链表
    		s->next = NULL;
    		p->next = s;
    		p = p->next;
    	}
    	printf("单链表创建成功!\n");
    }
    
    void DispList(LinkList *L)//遍历单链表
    {
    	LinkList p = *L, q = *L;
    
    	while(p->next)
    	{
    		p = p->next;
    		printf("%d ", p->Key);//关键字
    	}
    	printf("\n");
    	while(q->next)
    	{
    		q = q->next;
    		printf("%c ", q->info);//关键字信息
    	}
    	printf("\n\n");
    }
    
    LinkList Search_Seq01(LinkList *L, KeyType key)//顺序查找
    {
    	LinkList p = *L;
    	while(p->next)
    	{
    		p = p->next;
    		if(p->Key == key)
    			return p;
    	}
    	return p;
    }
    
    LinkList Search_Seq02(LinkList *L, KeyType key)//监视哨查找
    {
    	LinkList p;
    	for(p = (*L)->next; p->Key != key; p = p->next);
    	return p;
    }
    int main()
    {
    	LinkList L;
    	InitList(&L);	
    	CreateList(&L);
    	printf("遍历单链表:\n");
    	DispList(&L);
    	
    	LinkList m, n;
    
    	printf("顺序查找\nkey = 2\n");
    	m = Search_Seq01(&L, 2);
    	if(m)
    		printf("关键字信息为:%c\n\n", m->info);
    	else
    		printf("查找失败!\n");
    	
    	printf("监视哨顺序查找\nkey = 8\n");
    	n = Search_Seq01(&L, 8);
    	if(n)
    		printf("关键字信息为:%c\n\n", n->info);
    	else
    		printf("查找失败!\n\n");
    
    	return 0;
    }
    

     

    展开全文
  • 目录标题 顺序查找(又称为线性查找) 折半查找(又称为二分查找) 分块查找(又称为索引顺序查找) 三种查找算法的比较 顺序查找(又称为线性查找) 顺序查找的线性表定义如下: typedef struct { int key;...

    顺序查找(又称为线性查找)

    顺序查找的线性表定义如下:

    typedef struct
    {
    	int key;
    }Search;
    

    顺序查找的算法思想:
    将顺序表中数据元素存放在数组下标为1到n的位置上,而下标为0的位置空出来作为监视哨,在查找之前,先将要查找的关键字key存放到数组下标为0的位置上,然后从顺序表的最后一个元素开始,从后往前依次和key比较。最终返回数组中与key相等的元素的位置,若返回0,则表示查找失败;若返回非零的整数,则表示查找成功。

    在这里插入图片描述

    核心算法如下:

    //顺序查找 
    int SeqSearch (Search a[], int n, int key) 
    {
    	a[0].key = key;
    //用数组的a[0]元素存放关键字	
    	while (a[n].key != key)
    //从后往前查找	
    	{
    		n--;
    	}
    	return n;
    //返回该元素所在的数组的下标,若下标等于0,则表示表中无此关键字 	
    } 
    
    

    顺序查找的源代码:

    举例: 查找值为8的元素

    # include <stdio.h>
    # define MAX 10
    
    
    typedef struct
    {
    	int key;
    }Search;
    
    
    //顺序查找 
    int SeqSearch (Search a[], int n, int key) 
    {
    	a[0].key = key;
    //用数组的a[0]元素存放关键字	
    	while (a[n].key != key)
    //从后往前查找	
    	{
    		n--;
    	}
    	return n;
    //返回该元素所在的数组的下标,若下标等于0,则表示表中无此关键字 	
    } 
    
    
    int main (void)
    {
    	Search a[MAX];
    	int n, i;
    	printf ("请输入元素的个数:");
    	scanf ("%d", &n);
    	for (i = 1; i < n+1; i++)
    	{
    		printf ("a[%d] = ", i);
    		scanf ("%d", &a[i].key);
    	}
    	
    	i = SeqSearch (a, n+1, 8);
    	if (i == 0)
    	{
    		printf ("表中无此元素!!!");
    	} 
    	else
    	{
    		printf ("该元素的位置为:%d", i);
    	} 
    }
    

    运行结果:
    在这里插入图片描述

    折半查找(又称为二分查找)

    使用折半查找的前提条件:
    表中的关键字必须按照大小有序排序

    折半查找的算法思想:
    取中间元素作为比较对象,若要查找的元素与中间元素相等,则查找成功;若小于中间元素,则到中间元素的左半区继续查找;若大于中间元素,则到中间元素的右半区继续查找。不断重复上述过程,直到查找成功或查找失败。

    折半查找的主要步骤:
    (1)初始化查找范围,令low=1,high=n
    (2)求查找的中间项:mid=(low+high)/2
    (3)将要查找的关键字和中间项作比较:

    • 若相等,则查找成功,此时mid指向的位置就是要查找元素的位置
    • 若k小于关键字,则低位指针low不变,将高位指针high改为mid-1
    • 若k大于关键字,则高位指针high不变,将低位指针low改为mid+1

    (4)重复步骤(2)和(3),直到查找成功或查找失败(即low>high)
    (5)若查找成功,则返回要查找元素的位置,即当前指针mid;否则返回查找失败标志0

    其算法如下:

    //二分查找(折半查找)
    int BinSearch (Search a[], int n, int key) 
    {
    	int low = 1, high = n;
    	int mid;
    	while (high >= low)
    	{
    		mid = (low + high) / 2;
    		if (a[mid].key == key)
    		{
    			return mid;
    		}
    		else if (a[mid].key > key)
    		{
    			high = mid-1;
    		}
    		else
    		{
    			low = mid + 1;
    		} 
    	}
    	if (low>high)
    	{
    		return 0;
    	}
    }
    

    查找过程举例:

    对于关键字序列{2,4,6,9,10,13,18},采用折半查找法查找6和17的具体过程。

    (1)查找key=6的过程。
    初始时令low=1,high=7,则mid=4
    在这里插入图片描述
    此时因为key=6 < a[mid]=9,所以high=mid-1=3, mid=(low+high)/2=2
    在这里插入图片描述
    此时因为key=6 > a[mid]=4,所以low=mid+1=3, mid=(low+high)/2=3
    在这里插入图片描述
    因为此时key=a[mid]=6,所以查找成功,返回mid的值,即返回要查找元素的位置

    (1)查找key=17的过程。
    初始时令low=1,high=7,则mid=4
    在这里插入图片描述
    此时因为key=17 > a[mid]=9,所以low=mid+1=5, mid=(low+high)/2=6
    在这里插入图片描述
    此时因为key=17 > a[mid]=13,所以low=mid+1=7, mid=(low+high)/2=7
    在这里插入图片描述
    此时因为key=17 < a[mid]=18,所以high=mid-1=6, mid=(low+high)/2=6
    在这里插入图片描述
    因为此时high=6 < low=7,所以查找失败,返回失败标志0

    分块查找的源代码:

    举例:查找值为6的元素

    # include <stdio.h>
    # define MAX 10
    
    
    typedef struct
    {
    	int key;
    }Search;
     
    
    //二分查找(折半查找)
    int BinSearch (Search a[], int n, int key) 
    {
    	int low = 1, high = n;
    	int mid;
    	while (high >= low)
    	{
    		mid = (low + high) / 2;
    		if (a[mid].key == key)
    		{
    			return mid;
    		}
    		else if (a[mid].key > key)
    		{
    			high = mid-1;
    		}
    		else
    		{
    			low = mid + 1;
    		} 
    	}
    	if (low>high)
    	{
    		return 0;
    	}
    }
    
    
    int main (void)
    {
    	Search a[MAX];
    	int n, i;
    	printf ("请输入元素的个数:");
    	scanf ("%d", &n);
    	for (i = 1; i < n+1; i++)
    	{
    		printf ("a[%d] = ", i);
    		scanf ("%d", &a[i].key);
    	}
    	
        i = BinSearch (a, n+1, 6);
        if (i == 0)
        {
        	printf ("该表中无此元素!!!");
    	}
    	else
    	{
    		printf ("该元素的位置为:%d", i);
    	} 
    }
    

    运行结果:
    在这里插入图片描述

    分块查找(又称为索引顺序查找)

    使用分块查找的前提条件:
    将查找表分成若干块,每块中的元素存储顺序都是任意的,但块与块之间必须按照关键字的大小有序排列,即前一块的最大关键字要小于后一块中的最小关键字。

    基本准备:
    建立一个索引表,索引表的每一项对应线性表的一块,索引项由关键字域和指针域组成,关键字域存放相应块的最大关键字,指针域存放指向块内的第一个元素和最后一个元素的数组下标值。

    分块查找的线性表类型与顺序查找的类型相同,但是还需要定义一个索引表类型

    //索引表类型 
    typedef struct
    {
    	int low, high, key;
    //low表示块内低地址,high表示块内高地址,key表示块内最大关键字	
    }TypeIdx;
    
    typedef struct
    {
    	int key;
    }Search;
    

    我们可以设计一个数组a来存放关键字的信息,设计一个数组b来存放索引表的信息
    举例:对于关键字序列{6,12,7,10,9,22,15,20,18,26},我们可以将其分为两块,即{6,12,7,10,9}和{22,15,20,18,26},前一块的最大关键字12小于后一块的最小关键字15

    在这里插入图片描述

    在这里插入图片描述
    分块查找的算法思想:
    先采用折半查找法确定待查找元素属于哪一块(由于索引表是递增有序的,所以采用折半查找速度较快),再采用顺序查找法查找块内的元素。(由于每块内的元素个数少,所以对执行速度没有太大的影响)

    因为索引表需要根据线性表中的个元素的值来生成,所以为了生成索引表,要编写建立索引表的函数,其算法如下:

    //建立索引表 
    void CreateIdx (Search a[], TypeIdx b[], int m, int n)
    //m表示元素的总数,n表示每块中的元素个数
    {
    	int i, j, k, max;
    //用i表示a数组的下标值,k表示b数组的下标值	
    	for (i = 0, k = 0; i < m; i = i+n, k++)
    //用for循环将每块的最大关键字,低地址和高地址都确定下来	
    	{
    		max = a[i].key;
    //先将最大值设为第i个元素		
    		for (j = i+1; j < i+n && j < m; j++)
    		{
    			if (a[j].key > max)
    			{
    				max = a[j].key;
    			}
    		}
    		b[k].key = max;
    //确定该块的最大值元素			
    	
    		b[k].low = i;
    //确定该块的低地址		
    
    		if (i+n <= m)
    //当最后一块的长度小于n时		
    		{
    			b[k].high = i+n-1;
    		}
    		else		
    		{
    			b[k].high = m-1;
    		}
    //确定该块的高地址		
    	}
    }
    

    在线性表中查找关键字为k的元素。若找到,则返回它所在的位置;否则返回-1,其算法如下:

    int BlkSearch (int f, Search a[], TypeIdx b[], int k)
    //f是索引表的元素个数,k是要查找的关键字
    {
    	int i, j, mid;
    	int low = 0, high = f;
    	while (low <= high)
    	{
    		mid = (low + high)/2;
    		if (b[mid].key > k)
    		{
    			high = mid-1;
    		}
    		else if (b[mid].key < k)
    		{
    			low = mid+1;
    		}
    		else
    		{
    			low = mid; 
    			break;
    		}
    	}
    //用二分法找到要查找元素的所在块
    	
    	if (low < f)	
    	{
    		i = b[low].low;
    	    j = b[low].high;
    //将该块低,高地址分别赋值给i,j	
    	} 
        
        while (i <= j && a[i].key != k)
        {
        	i++;
    	}
    	
    	if (i > j)
    	{
    		return -1;
    	}
    	else
    	{
    		return i;
    //i表示要查找元素的位置		
    	}
    } 
    

    分块查找的源代码:

    举例:对于关键字序列{6,12,7,10,9,22,15,20,18,26},我们来查找关键字为9的元素

    # include <stdio.h>
    # include <math.h>
    # define MAX 100
    
    
    //索引表类型 
    typedef struct
    {
    	int low, high, key;
    //low表示块内低地址,high表示块内高地址,key表示块内最大关键字	
    }TypeIdx;
    
    typedef struct
    {
    	int key;
    }Search;
    
    
    //建立索引表 
    void CreateIdx (Search a[], TypeIdx b[], int m, int n)
    //m表示元素的总数,n表示每块中的元素个数
    {
    	int i, j, k, max;
    //用i表示a数组的下标值,k表示b数组的下标值	
    	for (i = 0, k = 0; i < m; i = i+n, k++)
    //用for循环将每块的最大关键字,低地址和高地址都确定下来	
    	{
    		max = a[i].key;
    //先将最大值设为第i个元素		
    		for (j = i+1; j < i+n && j < m; j++)
    		{
    			if (a[j].key > max)
    			{
    				max = a[j].key;
    			}
    		}
    		b[k].key = max;
    //确定该块的最大值元素			
    	
    		b[k].low = i;
    //确定该块的低地址		
    
    		if (i+n <= m)
    //当最后一块的长度小于n时		
    		{
    			b[k].high = i+n-1;
    		}
    		else		
    		{
    			b[k].high = m-1;
    		}
    //确定该块的高地址		
    	}
    } 
    
    
    //打印索引表 
    void DisIdx (int m, int n, Search a[], TypeIdx b[])
    {	
        int i;
    	printf ("建立的顺序表为:\n");
    	for (i = 0; i < m; i++)
    	{
    		printf ("%d    ", a[i].key);
    	} 
    	
    	CreateIdx (a, b, m, n);
    	
    	printf ("\n索引表信息如下:\n");
    	printf ("低地址    高地址   最大关键字\n");
    	for (i = 0; i < m/n; i++)
    	{
    		printf ("   %d         %d         %d\n", b[i].low, b[i].high, b[i].key);
    	}
    }
    
    
    int BlkSearch (int f, Search a[], TypeIdx b[], int k)
    //f是索引表的元素个数,k是要查找的关键字
    {
    	int i, j, mid;
    	int low = 0, high = f;
    	while (low <= high)
    	{
    		mid = (low + high)/2;
    		if (b[mid].key > k)
    		{
    			high = mid-1;
    		}
    		else if (b[mid].key < k)
    		{
    			low = mid+1;
    		}
    		else
    		{
    			low = mid; 
    			break;
    		}
    	}
    //用二分法找到要查找元素的所在块
    	
    	if (low < f)	
    	{
    		i = b[low].low;
    	    j = b[low].high;
    //将该块低,高地址分别赋值给i,j	
    	} 
        
        while (i <= j && a[i].key != k)
        {
        	i++;
    	}
    	
    	if (i > j)
    	{
    		return -1;
    	}
    	else
    	{
    		return i;
    //i表示要查找元素的位置		
    	}
    } 
    
    
    int main (void)
    {
    	Search a[MAX];
    	TypeIdx b[MAX];
    	int m, i, n, f;
    	printf ("请输入元素的个数:");
    	scanf ("%d", &m);
    	printf ("请依次输入各个元素(要求块内无序,块间有序)\n");
    	for (i = 0; i < m; i++)
    	{
    		scanf ("%d", &a[i].key);
    	}
    	printf ("\n请输入索引表每块的大小为:");
    	scanf ("%d", &n);
    	DisIdx (m, n, a, b);
     	 
     	f = ceil (m/n);
    //f为大于或等于m/n的最小整数 
     	i = BlkSearch (f, a, b, 9);
     	if (i == -1)
     	{
     		printf ("\n表中无此元素!!!"); 
    	}
    	else
    	{
    		printf ("\n该元素在表中的位置为:%d", i);
    	}
    }
    

    运行结果:
    在这里插入图片描述

    三种查找算法的比较

    优点缺点平均性能
    顺序查找对表中的数据如何存储没有要求平均查找长度较大,效率低
    折半查找比较次数少,查找速度快要求待查找的表必须为有序表,而且排序会很费时
    分块查找只要找到相应的块,插入或删除元素很容易要求待查找的表,块与块之间必须按关键字的大小有序排列介于二者之间
    展开全文
  • 顺序查找算法

    2021-08-24 08:34:29
    顺序查找比较简单,其执行的操作是从数据序列中的第1个元素开始,从头到尾依此逐个查找,直到找到所要的数据或搜索完整个数据序列。顺序查找主要针对少量的、无规则的数据。 对于包含n个数据的数据序列,使用顺序...
  • 顺序查找 按照顺序一个个查找 #include<stdio.h> //顺序查找 int search(int arr[],int len,int aim) { int i; for(i=0;i<len;i++) { if(arr[i]==aim) { return i;//返回下标 } } ...
  • 顺序查找、折半查找,都是在一个线性表中,查找指定的关键字。它们的区别是,折半查找需要该线性表本身是有序的,而顺序查找则没有这个限制。
  • 顺序查找、折半查找基础概念顺序查找一般线性表的顺序查找平均查找次数优缺点:有序表的顺序查找思路失败结点平均查找长度折半查找平均查找长度时间复杂度分块查找(索引顺序查找)思路步骤平均查找长度 基础概念 在...
  • 顺序查找是最简单、最直接的查找算法,顺序查找是将数列从头到尾按照顺序查找一遍,是一种最没有技术含量、最容易理解的算法。 算法思想 静态查找是指只在数列中查找特定的数字,不对数列做任何的修改(但是可以...
  • 查找--顺序查找

    2021-04-18 11:49:37
    定义顺序查找又称为线性查找,其算法思路是从数组中的第一个(或最后一个)记录开始,将数组中元素逐个与需要查找的关键字进行比对,若发现有相等的,则查找成功;若始终未能相等,则查找失败。Java实现// 定义接口...
  • 顺序查找JAVA实现

    2021-03-09 08:36:45
    顺序查找又称线性查找:基本思想:从查找表的一端开始,向另一端逐个按给定值K与关键字进行比较,若找到,查找成功;并给出记录在表中的位置;若整个表检测完,仍未找到与K值相同的关键字,则查找失败;优点:对表中...
  • 顺序查找:从表的一端开始,依次将记录在表中的关键字与给定值进行比较,若某个记录的关键字和给定值相同,则查找成功;反之查找失败。 顺序查找既适用于顺序表,又适用于线性表,首先先介绍顺序表中的顺序查找 ...
  • 1.顺序查找 顾名思义,就是按顺序往下一个一个查找,找到时返回,最差的情况是未找到并且全部遍历了一遍,这是消耗时间最长的一个方法 1.1代码实例:顺序查找 //顺序查找 int SeqSearch(RecType R[],KeyType x,int ...
  • 整理内容来源:zzu信息工程学院数据结构ppt 本节讨论两类不同的查找表:静态查找表和动态查找表,给出在不同查找表上进行查找的不同...顺序查找(适用于两种存储结构) 折半查找(有序表) 注意区分 “有序” 和
  • js实现顺序查找

    千次阅读 2021-01-26 09:29:59
    顺序查找:就是从第一个元素开始,按索引顺序遍历待查找序列,直到找出给定目标或者查找失败 时间复杂度:O(n) 应用:适合于存储结构为顺序存储或链接存储的线性表 const sequentialSearch = (arr, value) => { ...
  • 顺序查找和折半查找

    2020-12-23 14:51:29
    查找的基本概念 1)查找:在数据集合中寻找满足某种条件的数据元素的过程成为查找查找的结果一般分为两种:查找成功,即在数据集合中找到了满足条件的数据元素;另一种是查找失败。 2)查找表(查找结构):用于查找...
  • nbsp开发文档顺序表查找(顺序查找、二分查找) C语言实现.pdf5页本文档一共被下载:次,您可全文免费在线阅读后下载本文档。 下载提示1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔...
  • 本文实例为大家分享了C语言实现顺序表的顺序查找和折半查找的具体代码,供大家参考,具体内容如下顺序查找:#include using namespace std;int SeqSearch(int r[],int n,int k){r[0]=k;//下标0用作哨兵存放要查询的...
  • 顺序查找与二分查找的代码实现 顺序查找: 基本思想 1.依次扫描A中的所有元素,将每个元素与x比较; 2.如果在i次比较后1<=i<=n搜索成功,即x==A[j],则返回j的值; 3.否则返回0,表示没有找到。 对于一个大小...
  • 顺序查找算法C语言实现

    千次阅读 2021-10-23 18:27:42
    顺序查找算法 实现思想:静态查找表用顺序存储结构表示时,顺序查找的查找过程为:从表中的最后一个数据元素开始,逐个同记录的关键字做比较,如果匹配成功,则查找成功;反之,如果直到表中第一个关键字查找完也...
  • 顺序查找java实现

    2021-03-04 03:39:13
    顺序查找java实现package suanfa;public class OrderSearch {/**顺序查找平均时间复杂度 O(n)* @param searchKey 要查找的值* @param array 数组(从这个数组中查找)* @return 查找结果(数组的下标位置)*/public ...
  • 二分查找和顺序查找

    2021-03-22 16:01:17
    顺序查找可以处理有序数组,也可以处理无序数组,依次遍历数组,查找待找元素,其时间复杂度为o(n);折半查找只能处理有序数组,每次查找的过程中,都会将查找范围缩小一半,其时间复杂度为o(log2n),以2为底,n的...
  • 初识数组查找(顺序查找法和二分查找法)

    多人点赞 热门讨论 2021-09-23 23:20:03
    在计算机应用中,查找是常用的基本算法,一般有七大查找算法,分别为:顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找、哈希查找。 今天,forever 也是初识查找算法,就先来说说顺序查找和二分...
  • 5.3.顺序查找当数据项存储在诸如列表的集合中时,我们说它们具有线性或顺序关系。 每个数据项都存储在相对于其他数据项的位置。 在 Python 列表中,这些相对位置是单个项的索引值。由于这些索引值是有序的,我们可以...
  • leetcode 顺序查找,二分法,斐波那契查找,插值查找,分块查找
  • 我们抛开二分查找算法,如果有这样的一个需求,需要在一些数字中找出有没有某个数字,我们应该怎么做?1 首先我们会想到用什么数据结构存放这些数?数据结构就是计算机存储组织、组织数据的方式。可以这样理解,生活...
  • C语言实现顺序查找

    2021-12-01 23:50:55
    C语言顺序查找
  • C++实现顺序查找

    2021-06-29 11:18:25
    C++实现顺序查找 需求.给定一个元组和查找的数字,根据查找数字,返回数组中对应数字的下标(索引) 1、创建数组、查找数字、数组长度: int data[] = { 3,2,4,1,5,6 }; // 创建数组 int val = 1; // 要查找数 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 812,575
精华内容 325,030
关键字:

顺序查找