查找和查找算法(顺序查找)

本文介绍了查找的基本概念,如查找表、关键字和查找长度,接着详细讲解了顺序查找算法,包括无序和有序表的查找,并提供了C语言的代码示例。文章还探讨了顺序查找的优化策略,如设置哨兵、先排序和跳跃查找,以提高查找效率。
摘要由CSDN通过智能技术生成

一、查找的基本概念

1、基本概念

查找表(Search Table):由相同数据类型的数据元素构成的集合(线性表、树、散列表)。
关键字(key):数据元素中某个数据项,它可以标识一个数据元素,是唯一的。
查找(Searching):根据给定的某个值,在查找表中找到一个关键字等于给定值的数据元素。如果表中存在这样的一个数据元素,则称查找是成功的,否则查找是失败的。
静态查找表(Static Search Table):查找表中的数据元索不会发生变化。
动态查找表(Dynamic Search Table):查找表中的数据元素会发生变化(插入、修改和删除)。
查找长度(Search Length):在查找运算中,需要对比关键字的次数。
平均查找长度(ASL,Average Serach Length):所有查找过程中进行关键字比较次数的平均值,用于衡量查找算法的效率,包括成功和失败两种情况。
在这里插入图片描述

二、查找算法

1、顺序查找

顺序查找(线性查找):用于在静态的线性表(顺序表或链表)中进行查找。算法思想是从线性表的某一端开始,把表中的元素与关键字逐个比较(线性表的遍历)。

例子:
在这里插入图片描述

代码实现:

/*
 * 程序名:seqsearch.c,此程序演示顺序查找。
 * 作者:C语言技术网(www.freecplus.net) 日期:20210325
*/
#include <stdio.h>
#include <string.h>

// 对无序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search1(int *sstable,unsigned int len,int key)
{
  int ii;

  for (ii=0;ii<len;ii++)  // 从前往后或从后往前找都行。
    if (sstable[ii]==key) break;  // 找到了就break

  if (ii==len) return -1;  // 查找失败时,ii==len

  return ii;
}

/*
// 对无序的查找表进行顺序查找更精简的写法。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search1(int *sstable,unsigned int len,int key)
{
  int ii;

  for (ii=0;ii<len&&sstable[ii]!=key;ii++)  // 从前往后或从后往前找都行。
    ;

  return ii==len?-1:ii; 
}
*/

// 设置哨兵对无序的查找表进行顺序查找。
// 在sstable中查找key,失败返回0,成功返回key在sstable中的数组下标。
int Seq_Search2(int *sstable,unsigned int len,int key)
{
  int ii;

  sstable[0]=key;  // 哨兵。

  for (ii=len-1;sstable[ii]!=key;ii--)  // 从后往前找。
    ;                                   // 注意这个空语句。

  return ii;  // 找不到时,ii为0
}

// 对有序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search3(int *sstable,unsigned int len,int key)
{
  int ii;

  for (ii=0;ii<len;ii++)  // 从前往后或从后往前找都行。
  {
    if (sstable[ii]==key) break;  // 找到了就break
    if (sstable[ii] >key) return -1; // 不必再找了,返回-1
  }

  if (ii==len) return -1;  // 查找失败时,ii==len

  return ii;
}

// 采用跳跃的方法对有序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search4(int *sstable,unsigned int len,int key)
{
  int ii=0;

  while (ii<len && sstable[ii]<key) ii=ii+3;  // 每次跳跃三个元素。

  if (ii<len && sstable[ii]==key) return ii;  // 查找成功。 
  else if (ii-1<len && sstable[ii-1]==key) return ii-1;  // 查找成功。
  else if (ii-2<len && sstable[ii-2]==key) return ii-2;  // 查找成功。

  return -1;  // 查找失败。
}

int main()
{
  // 对无序的查找表进行顺序查找。
  int sstable1[]={2,5,6,3,1,7,4,8,9};
  int len=sizeof(sstable1)/sizeof(int);

  printf("result1=%d\n",Seq_Search1(sstable1,len,7));
  printf("result1=%d\n",Seq_Search1(sstable1,len,15));
  printf("result1=%d\n",Seq_Search1(sstable1,len,2));
  printf("result1=%d\n",Seq_Search1(sstable1,len,9));
  printf("\n");

  // 设置哨兵对无序的查找表进行顺序查找。
  int sstable2[]={0,2,5,6,3,1,7,4,8,9};
  len=sizeof(sstable2)/sizeof(int);

  printf("result2=%d\n",Seq_Search2(sstable2,len,7));
  printf("result2=%d\n",Seq_Search2(sstable2,len,15));
  printf("result2=%d\n",Seq_Search2(sstable2,len,2));
  printf("result2=%d\n",Seq_Search2(sstable2,len,9));
  printf("\n");

  // 对有序的查找表进行顺序查找。
  int sstable3[]={1,2,3,4,5,6,7,8,9};
  len=sizeof(sstable3)/sizeof(int);

  printf("result3=%d\n",Seq_Search3(sstable3,len,7));
  printf("result3=%d\n",Seq_Search3(sstable3,len,15));
  printf("result3=%d\n",Seq_Search3(sstable3,len,1));
  printf("result3=%d\n",Seq_Search3(sstable3,len,9));
  printf("\n");

  // 采用跳跃的方法对有序的查找表进行顺序查找。
  int sstable4[]={1,2,3,4,5,6,7,8,9};
  len=sizeof(sstable4)/sizeof(int);

  printf("result4=%d\n",Seq_Search4(sstable4,len,0));
  printf("result4=%d\n",Seq_Search4(sstable4,len,7));
  printf("result4=%d\n",Seq_Search4(sstable4,len,15));
  printf("result4=%d\n",Seq_Search4(sstable4,len,1));
  printf("result4=%d\n",Seq_Search4(sstable4,len,9));
  printf("\n");

  return 0;
}

顺序查找的优化方案

改善前:

// 对无序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search1(int *sstable,unsigned int len,int key)
{
  int ii;

  for (ii=0;ii<len;ii++)  // 从前往后或从后往前找都行。
    if (sstable[ii]==key) break;  // 找到了就break

  if (ii==len) return -1;  // 查找失败时,ii==len

  return ii;
}
1、设置哨兵方案

假设我需要在下图表中查找元素7;我们可以把7放在数组下标为0的位置,然后从数组的后面开始逐个元素和7比较;

改善后:

// 设置哨兵对无序的查找表进行顺序查找。
// 在sstable中查找key,失败返回0,成功返回key在sstable中的数组下标。
int Seq_Search2(int *sstable,unsigned int len,int key)
{
  int ii;

  sstable[0]=key;  // 哨兵。

  for (ii=len-1;sstable[ii]!=key;ii--)  // 从后往前找。
    ;                                   // 注意这个空语句。

  return ii;  // 找不到时,ii为0
}

由上面两段代码可知,循环的条件从判断 ii<len 变成了 sstable[ii]!=key,改善前的循环体还需要做两次判断,而改善后不需要,因而提高了效率;

2、先排序

假设我需要在下图有序表中查找元素23,可找到;
查找24时,查找到23,发现23<24,指针向后移动,发现25>24,此时就不会向后寻找了,因为数组时有序的,后面的数都比25大;

改善后:

// 对有序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search3(int *sstable,unsigned int len,int key)
{
  int ii;

  for (ii=0;ii<len;ii++)  // 从前往后或从后往前找都行。
  {
    if (sstable[ii]==key) break;  // 找到了就break
    if (sstable[ii] >key) return -1; // 不必再找了,返回-1
  }
  if (ii==len) return -1;  // 查找失败时,ii==len
  return ii;
}

这种情况对于成功的查找不会有什么改进,但是对于不存在的元素有比较大的效率改进;

3、跳跃

假设依旧是在下面有序表中,查找元素23,跳跃法,就是如果比较元素不一致,指针就向后跳动几个位置;

改善后:

// 采用跳跃的方法对有序的查找表进行顺序查找。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Seq_Search4(int *sstable,unsigned int len,int key)
{
  int ii=0;

//每次跳跃3个元素,自定,也可以跳跃少或者多几个
  while (ii<len && sstable[ii]<key) ii=ii+3;  // 每次跳跃三个元素。

  if (ii<len && sstable[ii]==key) return ii;  // 查找成功。 
  else if (ii-1<len && sstable[ii-1]==key) return ii-1;  // 查找成功。
  else if (ii-2<len && sstable[ii-2]==key) return ii-2;  // 查找成功。

  return -1;  // 查找失败。
}v

效率分析

无序查找表: 在这里插入图片描述
第一个元素需要比较1次,第二个2次,第3个3次,第n个n次;
ASL成功= (1+2+3+…n)/n=n(n+1)/2n=(n+1)/2
失败的话从表头到表尾,比较n次;
ASL失败=n;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值