线性查找与哨兵查找法

当我们在编写程序时,经常需要找寻一个数组或者字符串中某个元素的下标,本篇文章就对如何用最简单的方法找到该元素的下标进行了讲解。

线性查找(顺序查找)

简介

当我们需要找寻数组(字符串)中的目标元素的下标(位置)的时候,通常说要遍历整个数组(字符串)即可,此处提到的遍历,就是进行的线性查找,其过程就是按照顺序从头至尾按照下标依次寻找,直至找到目标元素或者找完整个数组(字符串)。

代码实现

#include <stdio.h>
#define arr_max 5 //数组元素的个数  

int search(const int arr[], int n, int val)//const修饰数组,防止数组中的元素改变
{
	int i = 0;
	while(1)
	{
		if(i == n)
			return -1; //全部找过,没找到,返回-1作为标记
		if(arr[i] == val)
			return i;  //找到目标元素,返回其下标
		i++;
	}
	
}
int main()
{
	int i,num;
	int arr[arr_max];
	for(i = 0; i < arr_max; i++)
	{
		scanf("%d", &arr[i]);
	}
	scanf("查找的元素是%d", &num);
	int ret = search(arr, arr_max, num);
	if(ret==-1)   //通过返回值判断是否找到
		printf("元素不存在\n");
	else
		printf("找到了,下标是%d\n",ret);
	return 0;
}

在传参的时候,数组中的元素不需要被修改,所以最好加上 const 修饰,避免改变数组中的数值。
本代码还可改进,当编译器支持变长数组时,可把#define arr_max 5的内容改为在 main 函数内部定义一个数组大小的变量 arr_max,然后再使用 scanf("%d", &arr_max) 输入一个数值即可。

函数 seach 从数组的第一个元素开始,依次判断是否存在和 val 相同的元素,如果有,则返回其下标,若将所有元素判断过之后仍没有,则返回 -1作为没找到的标记,因为数组中的任何一个元素的下标都不可能等于 -1(使用其他不能能是数组中元素下标的值也可以)。
函数 seach 中使用 while 循环,且循环判断条件为 1,循环中不存在 break 跳出循环,所以只有遇到 return 时才会跳出循环。所以只有找到目标元素或者查找一遍之后才会结束循环。

像这样,从数组的开头开始出发,按照顺序依次查找,直至找到目标元素或者找完整个数组没找到。像这样的一系列操作被称为线性查找或者线性查找

哨兵查找法

简介

在线性查找的时候,循环过程中需要不断判断是否满足结束循环的两个条件是否满足,当数组较小的时候,对程序并没有太大的影响,但是当数组中的元素较多的时候,多次的循环判断对代码的运行速度将会产生不小的影响。

如果数组(字符串)中的元素(个数)还有剩余,我们就可以把数组中的最后一个元素的后面放入目标元素,这这样我们就不需要每次循环就去判断还否到末尾,只需要在找到目标元素后判断其位置是在数组中还是在最后就可以了。

当找到的目标元素不在末尾时,就证明找到了目标元素,返回其下标即可。
到找到的目标元素在末尾时,就证明没有找到目标元素,返回 -1或者其他不不可能是下标的数值作为标记即可。

在数组末尾追加的数据成为“哨兵”,使用哨兵进行查找的方法称为“哨兵查找法”,使用哨兵可以简化对循环的判断条件。

代码实现

#include <stdio.h>
#define arr_max 5 //数组元素的个数  

int search(int arr[], int n, int val)//数组不可用const修饰,因为需要修改数组。
{
	int i = 0;
	arr[n] = val; //添加哨兵
	while(1)
	{
		if(arr[i] == val)
			break;  //找到目标元素,结束循环
		i++;
	}
	return (i < n) ? i : -1;
}
int main()
{
	int i,num;
	int arr[arr_max + 1]; //数组多创建一个位置留给哨兵
	for(i = 0; i < arr_max; i++)
	{
		scanf("%d", &arr[i]);
	}
	scanf("查找的元素是%d", &num);
	int ret = search(arr, arr_max, num);
	if(ret==-1)   //通过返回值判断是否找到
		printf("元素不存在\n");
	else
		printf("找到了,下标是%d\n",ret);
	return 0;
}

当不是数组而是字符串时,修改后的字符串需要再修改回来,因为字符串要以 \0 作为字符串的结束标志,如果不修改为原字符串,则会使字符串的长度和内容发生不可预测的变化。

在创建数组时,需要多开一个元素的空间,作为储存哨兵的位置
search 函数需要修改数组 arr 中的内容,所以在 search 函数接受参数的时候,不可以加 const 修饰
search 函数中的判断条件由两个变为一个,if 语句的判断次数减小了,代码的运行速度也增加了
search 函数的返回值是一个三目操作符,其作用是判断找到的目标值是数组中的值还是哨兵,并通过判断结果返回其下标或者 -1。

特别注意

我们需要知道,数组的大小应该是没有哨兵位置的大小的,但实际上我们为了使用哨兵法多开了一个元素的空间,所以我们在计算数组大小时的代码应该是数组的总长度减去一个元素。
例如求数组字节时int sz = sizeof(arr) - sizeof(arr[n]);需减去最后一个元素的字节大小。
求数组长度时int sz = sizeof(arr)/sizeof(arr[0]) - 1;int sz = (sizeof(arr)-sizeof(arr[n]))/sizeof(arr[0])需减去最后一个元素的大小。

  • 52
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雾里看山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值