【查找算法】解析学习四大常用的计算机查找算法 | C++

news2025/1/12 8:43:46

第二十二章    四大查找算法


目录

第二十二章    四大查找算法

●前言

●查找算法

●一、顺序查找法

1.什么是顺序查找法?

2.案例实现

●二、二分查找法

1.什么是二分查找法?

2.案例实现

●三、插值查找法

1.什么是插值查找法?

2.案例实现

●四、斐波那契查找法

1.什么是斐波那契查找法?

2.案例实现

●总结


前言

        在数据处理的过程中,能否在最短时间内去找到目的数据,是编程开发人员非常值得关心的一个问题。所谓查找,也被称为搜索,它是指从数据文件中找出满足某些条件的记录。在数据结构中描述算法时习惯用“查找”,而在搜索引擎中找信息或资料时习惯用“搜索”。我们在电话簿中查找某人的电话号码,电话簿就像是数据文件库,而姓名就是去查找电话号码的键值。我们经常使用的搜索引擎所设计的Spider程序(网页抓取程序爬虫)会主动经由网站上的超链接“爬行”到另一个网站,搜集每个网站上的信息并且收录到数据库中,这其中就涉及到了今天要讲的查找算法。


查找算法

        在查找算法中,比较常见的有顺序法、二分法、插入法和斐波那契法等。查找的操作和算法有关,具体的操作方式和进行方式与所选择的数据结构有关。计算机查找数据的优点就是快速,但是对于不同程度下的数据量,查找可以分为内部查找(数据量较小的文件)和外部查找(数据量较大的文件)。影响查找时间长短的主要因素有算法,数据存储的方式以及结构。查找可以分为静态查找和动态查找。静态查找是指数据元素在查找的过程中不会有添加,删除,更新等操作。动态查找是指所查找的数据在查找过程中会经常地添加,删除或更新。


一、顺序查找法

1.什么是顺序查找法?

(1)简要介绍

        顺序查找法是一种比较简单的查找法。该算法就是利用了计算机便于处理大量数据的这一特点,从而来进行实现的。该方法的优点就是文件在查找前不需要进行任何处理与排序;而缺点是查找的速度比较慢,因为无论数据顺序是什么情况,它都需要从头到尾都去遍历一遍。如果数据元素没有重复,那么找到数据元素就可以中止查找。说明最差的情况是n次查找,最好的情况下是1次查找。

(2)具体情况

        在8个数据元素中,去顺序查找元素89。情况如下图所示:

对于大量重复的数据元素来说,顺序查找法一般是不会使用的,因为它的时间效率极低并且可能会因为元素中的重复项而造成错误。但是对于少量的数据元素来说,这无疑是一种非常快又准确性高的简单方法。

(3)算法分析

        ①时间复杂度:如果数据没有重复且找到数据就可以中止,那么在最差情况下就是未找到数据,进行了n次比较,所以时间复杂度为O(n)。

        ②当数据量很大时,不适合使用顺序查找法。如果事先预估到所查找的数据在文件前面的部分,就可以减少查找的时间。

        ③在平均情况下,假设数据出现的概率相等,则需要进行(n+1)/2次比较。

2.案例实现

(1)范例情况:用随机法生成80个1~100的整数,用顺序查找法去查找我们指定元素是否存在,如果存在说明其所在的位置。

(2)代码展示:

#include<iostream>
#include<cstdlib>
using namespace std;
class order {
public:
	int data[80];
	int val = 0;
	//构造函数 随机给data中分配数据
	order() {
		for (int i = 0; i < 80; i++)
			data[i] = (rand() % 100) + 1;
	}
	void order_start() {
		cout << "请输入要猜测的数:";
		cin >> val;
		for (int i = 0; i < 80; i++)
		{
			if (data[i] == val) {
				cout << "该数" << data[i] << "存在 所在位置为" << i + 1 << endl;
				val = 0;
			}
		}
		if (val != 0)
			cout << "该数不存在" << endl;
	}
	//析构函数 展现所有元素
	~order() {
		cout << "所有随机数据元素如下:" << endl;
		for (int i = 0; i < 80; i++) 
			cout << data[i] << "[" << i << "]" << " ";
	}
};
int main()
{
	order o;
	while (o.val != -1)
	{
		o.order_start();
	}
}

(3)结果展示:

二、二分查找法

1.什么是二分查找法?

(1)简要介绍

        如果一组数据已经事先排好了顺序,那么就可以用二分查找法来进行查找。二分查找法的基本方法就是将数据分成两等份,比较目标寻找值与中间值的大小。如果小于中间值,那么我们就可以确定要寻找的数据在前半部分,否则在后半部分。重复上述步骤将其分割直到找到或确定不存在为止。

(2)具体情况

        用二分查找法对已经完成排序的一组数列,查找其元素101所在的位置。具体情况如下图所示:

 (3)算法分析

        ①时间复杂度:因为每次的查找都会比上一次查找少一半的范围,所以最多只需比较(log2^n)+1或(log2^(n+1))次,时间复杂度O(log2^n)。

        ②二分查找法必须是经过排序的数列,且数据元素都要加载到内存中才能进行查找。

        ③二分查找法适用于不需要增删的静态数据。

2.案例实现

(1)范例程序:用二分查找法查找10个1~10随机数据中指定数据元素的位置,并且输出随机产生的这10个数据。

(2)代码展示:

#include<iostream>
using namespace std;
#define size 10
class dichotomy {
public:
	int data[size];
	int val = 0;
	dichotomy() {
		for (int i = 0; i < size; i++)
			data[i] = (rand() % 10) + 1;
	}
	void sort() {
		for (int i = 0; i < size-1; i++) {
			for (int j = i+1; j < size; j++) {
				if (data[i] > data[j])
				{
					int temp;
					temp = data[i];
					data[i] = data[j];
					data[j] = temp;
				}
			}
		}
	}
	void dichotomy_start(int len_left,int len_right){ 
		int record=0;
		while (len_left <= len_right )
		{
			int mid = (len_right + len_left) / 2;
			if (val < data[mid]) {
				cout << "目标数在中间值的左边" << endl;
				len_right = mid - 1;
			}
			else if (val > data[mid]) {
				cout << "目标数在中间值的右边" << endl;
				len_left = mid + 1;
			}
			else if(val==data[mid]){
				cout << "在第" << mid + 1 << "个位置处找到了" << "该元素" << data[mid] << endl;
				val = 1;
				break;
			}	
		}	
		if (val != 1) {
			cout << "随机产生的这几个数中不存在要猜测的这个数值" << endl;
		}
	}
	~dichotomy() {
		cout << "所有随机数据元素如下:" << endl;
		for (int i = 0; i < size; i++) 
			cout << data[i] << "[" << i << "]" << " ";
	}
};
int main()
{
	dichotomy d;
	d.sort();
	while (d.val!=-1)
	{
		cout << "请输入要猜测的数:";
		cin >> d.val;
		if (d.val != -1)
			d.dichotomy_start(0, size - 1);
		else
			break;
	}
}

(3)结果展示:

三、插值查找法

1.什么是插值查找法?

(1)简要介绍

        插值查找法又被称为插补查找法,是对二分查找的进一步改进。它是按照数据位置的分布,利用公式去预测数据所在的位置,再用二分法的方式渐渐逼近。该查找法的公式如下:

其中,key是要去查找的键值,data[high],data[low]是剩余待查找记录中的最大值和最小值。特别注意:使用该查找算法之前需要对要排序的数据进行排序。

(2)具体情况

假设数据项为n,其插值查找法的步骤如下:

        ①讲记录从小到大的顺序给予1,2,...,n的编号;

        ②令low=1,high=n;

        ③当low<high时,重复执行步骤④和步骤⑤;

        ④令Mid=low+((key-data[low])/(data[high]-data[low]))*(high-low);

        ⑤若key<key[mid]且high≠Mid-1,则令high=Mid-1;

        ⑥若key>key[mid]且low≠Mid+1,则令low=Mid+1;

        ⑦若key=key[mid],则表示成功找到了键值的位置;

简单示例

 (3)算法分析

        ①插值查找法优于顺序查找法,如果数据的分布越平均,查找速度就越快,甚至可能第一次就找到数据。插值查找法的时间复杂度取决于数据的分布情况,平均而言优于O(log2^n)。

2.案例实现

①范例程序:用插值查找法去查找10个随机数据中,指定元素数据所在的位置。

②代码展示:

#include<iostream>
using namespace std;
class interpolation_search {
public:
	int data[10];
	int val = 0;
	interpolation_search() {
		for (int i = 0; i < 10; i++)
			data[i] = (rand() % 10) + 1;
	}
	void sort() {
		for (int i = 0; i < 10-1; i++)
		{
			for (int j = i + 1; j < 10; j++)
			{
				if (data[i] > data[j])
				{
					int temp;
					temp = data[i];
					data[i] = data[j];
					data[j] = temp;
				}
			}
		}
	}
	void interpolation_search_start() {
		int low = 0, high = 9;
		while (low<=high)
		{
			int mid = low + ((val - data[low]) / (data[high] - data[low])) * (high - low);
			if (val < data[mid]) {
				cout << "目标元素在mid的左边" << endl;
				high = mid - 1;
			}
			if (val > data[mid]) {
				cout << "目标元素在mid的右边" << endl;
				low = mid + 1;
			}
			if (val == data[mid]) {
				cout << "找到了该元素,该元素位置在" << mid + 1 << "处" << endl;
				val = 1;
				break;
			}
		}
		if (val != 1) {
			cout << "随机生成的数据中没有你要去查找的数据" << endl;
		}
	}
	~interpolation_search() {
		cout << "随机产生的数据元素如下" << endl;
		for (int i = 0; i < 10; i++)
			cout << data[i] << " ";
	}
};
void text()
{
	interpolation_search is;
	is.sort();
	while (is.val != -1)
	{
		cout << "请输入你要查找的数:";
		cin >> is.val;
		is.interpolation_search_start();
	}
}
int main()
{
	text();
}

③结果展示:

 四、斐波那契查找法

1.什么是斐波那契查找法?

(1)简要介绍

        斐波那契查找法又被称为斐氏查找法,该方法与二分法一样都是以分割范围来进行查找的,不同的是该方法不是以对半的方式来进行分割的,而是利用斐波那契级数(0、1、1、2、3、5、8、13、21、34、55、...)来进行分割的。该查找法的优点就是只需要用到加减运算,这从计算机运算的底层来看效率是相对较高的。并且该查找法会用到斐波那契树,所以我们应该先来了解该树的基本情况和特点。

(2)具体情况

斐波那契树的建立原则:

        ①斐波那契树的左右子树都是斐波那契树。

        ②斐波那契树的树根一定是一个斐波那契数,且子节点与父节点之间的差值的绝对值仍为斐波那契数。

        ③当k≥2时,斐波那契树的树根为Fib(k),左子树为(k-1)层斐波那契树,右子树为(k-2)层斐波那契树。

        ④当数据个数n确定时,若想确定斐波那契树的层数k为多少,必须找到一个最小的k值,使斐波那契层数的Fib(k+1)≥n+1。

 也就是说当数据个数为n,我们找到一个最小的斐波那契数Fib(k+1)使得Fib(k+1)>n+1时,Fib(k)就是这棵树的树根,而Fib(k-2)就是与左右子树开始的差值,左子树去减,右子树去加。例如去求取n=33的斐波那契树。由于n=33,则n+1=34为一棵斐波那契树。由斐波那契公式可得知Fib(0)=0,Fib(1)=1,Fib(2)=1,Fib(3)=2,Fib(4)=3,Fib(5)=5,Fib(6)=8,Fib(7)=13,Fib(8)=21,Fib(9)=34。可知Fib(k+1)≥n+1为Fib(8+1)=34,k=8所以建立二叉树的树根为Fib(8)=21。左子树的树根为Fib(8-1)=13;右子树的树根为Fib(8)+Fib(8-2)=21+8=29;从而依照上述步骤建立的斐波那契树如下图所示:

若我们要查找的键值为key,首先要去比较数组下标Fib(k)和键值key,此时就将会出现多种情况如下:

        ①key值较小,落在了1~Fib(k)-1位置上,所以继续去查找1~Fib(k)-1的数据;key值较大,落在了Fib(k)+1~Fib(k+1)-1的位置上,所以继续去查找Fib(k)+1~Fib(k+1)-1的数据。

        ②当键值与数组下标Fib(k)的值相等时,则表示成功的查找到了目标数据元素的位置。

(3)算法分析

       ① 斐波那契查找法虽然平均比较次数少于二分查找法,但在最坏的情况下还是二分查找法较快,并且斐波那契查找法相对复杂,因为它需要去额外产生一棵斐波那契树。

2.案例实现

①范例程序:用斐波那契树查找法去查找指定键值是否存在,并且如果存在其在哪个具体的位置。

②代码展示:

#include<iostream>
using namespace std;
#define size 10
class Fib {
public:
	int data[size];
	int val = 0;
	Fib() {
		for (int i = 0; i < size; i++)
			data[i] = (rand() % 10) + 1;
	}
	int Fib_start(int n) {
		if (n == 0 || n == 1)
			return 1;
		else
			return Fib_start(n - 1) + Fib_start(n - 2);
	}
	int Fib_search_start() {
		int index = 2;
		while (Fib_start(index) <= size)
			index++;
		index--;
		int rootnode = Fib_start(index);
		int diff_1 = Fib_start(index - 1);
		int diff_2 = rootnode - diff_1;
		rootnode--;
		while (1)
		{
			if (val == data[rootnode])
			{
				return rootnode;
			}
			else
			{
				if (index == 2)
					return size;
				if (val < data[rootnode])
				{
					rootnode = rootnode - diff_2;
					int temp = diff_1;
					diff_1 = diff_2;
					diff_2 = temp - diff_2;
					index = index - 1;
				}
				else
				{
					if (index == 3)
						return size;
					rootnode = rootnode + diff_2;
					diff_1 = diff_1 - diff_2;
					diff_2 = diff_2 - diff_1;
					index = index - 2;
				}
			}
		}
	}
	~Fib()
	{
		cout << "随机生成的所有数据情况如下" << endl;
		for (int i = 0; i < 10; i++)
			cout << data[i] << " ";
	}
};
void text()
{
	Fib f;
	while (f.val != -1)
	{
		cout << "请输入要查找的值:";
		cin >> f.val;
		int count = f.Fib_search_start();
		if(count==size)
			cout << "没有找到该数据元素" << endl;
		else
			cout << "在第" << count + 1 << "个位置找到了该数据元素" << f.val << endl;
	}
}
int main()
{
	text();
}

③结果展示:


总结

        以上就是我们对四类查找算法的分析与学习,查找算法在程序设计问题中经常作为一种重要中间的步骤。比如查找数据后,再对数据进行指定步骤的操作行为,所以要在不同的算法题型中合理地运用查找算法,从而达到最高的效率来解决相应的问题。

                                               <您的三连和关注是我最大的动力>

                       🚀 文章作者:Keanu Zhang        分类专栏:算法之美(C++系列文章)

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构:基数排序

基数排序(radix sorting) 实现排序主要是通过关键字之间的比较和移动记录这两种操作来完成的,而实现基数排序不需要进行关键字间的比较,而是利用“分配”和“收集”两种基本操作。 例如,我们可以用分配和收集的方法来对扑克牌进行“排序” 已知扑克牌中 52 张牌面的次序关系为…

Time-distributed 的理解

前言 今天看到论文中用到 Time-distributed CNN&#xff0c;第一次见到 Time-distributed&#xff0c;不理解是什么含义&#xff0c;看到代码实现也很懵。不管什么网络结构&#xff0c;外面都能套一个TimeDistributed。看了几个博客&#xff0c;还是不明白&#xff0c;问了问C…

Python数据挖掘基础

一、Matplotlib 画二维图表的python库&#xff0c;实现数据可视化 &#xff0c; 帮助理解数据&#xff0c;方便选择更合适的分析方法1、折线图1.1引入matplotlibimport matplotlib.pyplot as plt %matplotlib inlineplt.figure() plt.plot([1, 0, 9], [4, 5, 6]) plt.show()1.2…

知识探索项目测试报告

⭐️前言⭐️ 本篇文章是博主基于知识探索项目所做的测试报告&#xff0c;主要涉及到的测试知识有设计测试用例、自动化测试等测试知识。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获…

基于springboot+vue的药物咨询平台

基于springbootvue的药物咨询平台 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&…

二阶段提交事务的实现和缺点

背景 说起分布式事务&#xff0c;我们最绕不开的一个话题就是该不该使用分布式事务&#xff0c;而要理解为什么做出使用与否的决定&#xff0c;就必须要提到分布式事务中的最经典的实现&#xff1a;两阶段提交事务,本文我们就简答介绍下这个两阶段提交事务以及它的优缺点 技术…

【Opencv 系列】 第6章 人脸检测(Haar/dlib) 关键点检测

本章内容 1.人脸检测&#xff0c;分别用Haar 和 dlib 目标&#xff1a;确定图片中人脸的位置&#xff0c;并画出矩形框 Haar Cascade 哈尔级联 核心原理 &#xff08;1&#xff09;使用Haar-like特征做检测 &#xff08;2&#xff09;Integral Image : 积分图加速特征计算 …

SpringSecurity的权限校验详解说明(附完整代码)

说明 SpringSecurity的权限校是基于SpringSecurity的安全认证的详解说明(附完整代码) &#xff08;https://blog.csdn.net/qq_51076413/article/details/129102660&#xff09;的讲解&#xff0c;如果不了解SpringSecurity是怎么认证&#xff0c;请先看下【SpringSecurity的安…

【1792. 最大平均通过率】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 一所学校里有一些班级&#xff0c;每个班级里有一些学生&#xff0c;现在每个班都会进行一场期末考试。给你一个二维数组 classes &#xff0c;其中 classes[i] [passi, totali] &#xff0c;表示你…

0xL4ugh 2023

这回跟着个队伍跑&#xff0c;不过还是2X以后的成绩&#xff0c;前边太卷了。自己会的部分&#xff0c;有些是别人已经提交了的。记录一下。Cryptocrypto 1给了一些数据&#xff0c;像这样就没有别的了ct [0, 1, 1, 2, 5, 10, 20, 40, 79, 159, 317, 635, 1269, 2538, 5077, 1…

2023.02.19 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.本文贡献5.方法5.1 Local Representation Learning5.2 Global Representation Learning5.3 Item Similarity Gating6.实验6.1 数据集6.2 结果7.结论深度学习1.对偶问题1.1 拉格朗日乘数法1.2 强对偶性2.SVM优化3.软间隔3.1 解决问题3.…

尚医通 (十八)微信登录

目录一、生成微信登录二维码1、准备工作2、后端开发service_user3、前端显示登录二维码4、二维码出现不了进行调试二、开发微信扫描回调1、准备工作2、后台开发3、前台开发三、分析代码四、bug一、生成微信登录二维码 1、准备工作 1、注册 2、邮箱激活 3、完善开发者资料 4、…

JSP中http与内置对象学习笔记

本博文讲述jsp客户端与服务器端的http、jsp内置对象与控制流和数据流实现 1.HTTP请求响应机制 HTTP协议是TCP/IP协议中的一个应用层协议&#xff0c;用于定义客户端与服务器之间交换数据的过程 1.1 HTTP请求 HTTP请求由请求行、消息报头、空行和请求数据4部分组成。 请求行…

ThreeJS 之界面控制

文章目录参考描述界面自适应问题resize 事件修改画布大小修改视锥体的宽高比全屏显示dblclick 事件检测全屏显示状态进入全屏显示状态退出全屏显示状态尾声参考 项目描述ThreeJS官方文档哔哩哔哩老陈打码搜索引擎BingMDN 文档document.mozFullScreenElementMDN 文档Element.re…

LeetCode题目笔记——6359. 替换一个数字后的最大差值

文章目录题目描述题目链接题目难度——简单方法一&#xff1a;替换代码/Python代码优化总结题目描述 给你一个整数 num 。你知道 Danny Mittal 会偷偷将 0 到 9 中的一个数字 替换 成另一个数字。 请你返回将 num 中 恰好一个 数字进行替换后&#xff0c;得到的最大值和最小值…

CTK学习:(一)编译CTK

CTK插件框架简介 CTK Plugin Framework是用于C++的动态组件系统,以OSGi规范为模型。在此框架下,应用程序由不同的组件组成,遵循面向服务的方法。 ctk是一个开源项目,Github 地址:https://github.com/commontk。 源码地址commontk/CTK: A set of common support code for…

信小程序点击按钮绘制定制转发分享图

1. 说明 先上代码片断分享链接&#xff1a; https://developers.weixin.qq.com/s/vl3ws9mA72GG 使用 painter 画图 按钮传递定制化信息 效果如下&#xff1a; 2. 关键代码说明 文件列表如下&#xff1a; {"usingComponents": {"painter": "/com…

基于springboot的停车场管理系统(程序+文档)

大家好✌&#xff01;我是CZ淡陌。将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路。 &#x1f345;更多优质项目&#x1f447;&#x1f…

Android实例仿真之二

目录 三 从无入手 第一阶段 第二阶段 第三阶段 第四阶段 第五阶段 第六阶段 第七阶段 八 举两个典型例子&#xff1a; 九 逆向工程 三 从无入手 这节标题叫从无入手&#xff0c;什么意思呢&#xff1f;如果没有Android这个实例存在&#xff0c;你要做一个类似Android…

Mysql数据库事务

数据库事务 数据库事务由一组sql语句组成。 所有sql语句执行成功则事务整体成功&#xff1b;任一条sql语句失败则事务整体失败&#xff0c;数据恢复到事务之前的状态。 Mysql 事务操作 开始事务 start transaction;- 或 begin;事务开始后&#xff0c;对数据的增删改操作不…