【算法篇C++实现】常见查找算法

文章目录

  • 🚀一、预备知识
    • ⛳(一)查找的定义
    • ⛳(二)数组和索引
  • 🚀二、二分查找
  • 🚀三、穷举搜索
  • 🚀四、并行搜索
    • ⛳(一)并发的基本概念
    • ⛳(二)线程演示代码


🚀一、预备知识

⛳(一)查找的定义

查找: 又称检索或查询,是指在查找表中找出满足一定条件的结点或记录对应的操作。

查找表: 在计算机中,是指被查找的数据对象是由同一类型的记录构成的集合,如顺序表,链表、二叉树和哈希表等

查找效率: 查找算法中的基本运算是通过记录的关键字与给定值进行比较,所以查找的效率同常取决于比较所花的时间,而时间取决于比较的次数。通常以关键字与给定值进行比较的记录个数的平均值来计算。

查找操作及分类:

  1. 操作

    • 查找某个“特定的”数据元素是否存在在查找表中
    • 某个“特定的”数据元素的各种属性
    • 在查找表中插入一个数据元素
    • 从查找表中删除某个数据元素
  2. 分类

    若对查找表只进行( 1 ) 或( 2 )两种操作,则称此类查找表为 静态查找表

    若在查找过程中同时插入查找表中存在的数据元素,或者从查找表中删除已存在的某个数据元素,则称此类查找表为 动态查找表

⛳(二)数组和索引

日常生活中,我们经常会在电话号码簿中查阅“某人”的电话号码,按姓查询或者按字母排序查询; 在字典中查阅“某个词”的读音和含义等等。在这里,“电话号码簿”和“字典”都可看作一张查找表, 而按“姓”或者“字母”查询则是按索引查询

索引: 索引把线性表分成若干块,每一块中的元素存储顺序是任意的,但是块与块间必须按关键字大小按顺序排列。即前一块中的最大关键字值小于后一块中的最小关键字值。

索引表: 分块以后,为了快速定义块,还需要建立一个索引表,索引表中的一项对应于线性表中的一块,索引项由键域和链域组成。键域存放相应关键字的键值,链域存放指向本块第一个节点和最后一个节点的指针,索引表按关键字由小到大的顺序排列!

例子:

1、数组是特殊的块索引(一个块一个元素):

在这里插入图片描述

2、哈希表是非常经典的块索引!

在这里插入图片描述

分块查找的算法分两步进行,首先确定所查找的节点属于哪一块,即在索引表中查找其所在的块,然后在块内查找待查询的数据。由于索引表是递增有序的,可采用二分查找,而块内元素是无序的,只能采用顺序查找。(块内元素较少,则不会对执行速度有太大的影响)

🚀二、二分查找

算法精炼: 二分查找法实质上是不断地将有序数据集进行对半分割,并检查每个分区的中间元素。再重复根据中间数确定目标范围并递归实行对半分割,直到中间数等于待查找的值或是目标数不在搜索范围之内

C语言代码实现:

//二分查找的循环方法
int BinaryResearch(int arr[],int len,int e)
{int left = 0;int right = len - 1;int mid = right / 2;while (left<right){if (arr[mid] == e) return mid;if (e < arr[mid]){right = mid - 1;mid = (right + left) / 2;}	else{left = mid + 1;mid = (right + left) / 2;}	}
}//二分查找的递归方法
int BinaryResearch(int arr[], int left,int right, int e)
{if (left < right){int mid = (right + left) / 2;if (arr[mid] == e) return mid;if (e < arr[mid])return BinaryResearch(arr, left, mid - 1, e);elsereturn BinaryResearch(arr, mid + 1, right, e);}}

🚀三、穷举搜索

算法精炼: 列举出所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的全部解答

它利用计算机运算速度快、精确度高的特点,对要解决问题的所有可能情况,一个不漏地进行检查,从中找出符合要求的答案。

分析步骤:

用穷举算法解决问题,通常可以从两个方面进行分析:

  1. 问题所涉及的情况:问题所涉及的情况有哪些,情况的种数必须可以确定。把它描述出来。应用穷举时对问题所涉及的有限种情形必须一一列举,既不能重复,也不能遗漏。重复列举直接引发增解,影响解的准确性;而列举的遗漏可能导致问题解的遗漏。
  2. 答案需要满足的条件:分析出来的这些情况,需要满足什么条件,才成为问题的答案。把这些条件描述出来。

C语言代码实现:

例子:有 20 枚硬币,可能包括 4 种类型: 1 元、 5 角、 1 角和 5 分。已知 20 枚硬币的总价值为 10 元,求各种硬币的数量。例如: 4 、 11 、 5 、 0 就是一种方案。而 8 、 2 、 10 、 0 是另一个可能的方案,显然方案并不是唯一的,请编写程序求出类似这样的不同的方案一共有多少种?

穷举思路:

直接对四种类型的硬币的个数进行穷举。其中,1 元最多 10 枚、5 角最多 20 枚、1 角最多20 枚、5 分最多 20 枚。

//避免出现小数,将1元化作100分
int CoinCount(int a1, int a2, int a3, int a4,int total,int size_max)
{//记录最多使用每种硬币多少个int max1 = total / a1 > size_max ? size_max : total / a1;int max2 = total / a2 > size_max ? size_max : total / a2;int max3 = total / a3 > size_max ? size_max : total / a3;int max4 = total / a4 > size_max ? size_max : total / a4;int i = 0;for (int size_a1 = 0; size_a1 < max1; size_a1++)for (int size_a2 = 0; size_a2 < max2; size_a2++)for (int size_a3 = 0; size_a3 < max3; size_a3++)for (int size_a4 = 0; size_a4 < max4; size_a4++)if ((size_a1 * a1 + size_a2 * a2 + size_a3 * a3 + size_a4 * a4) == total&&(size_a1+size_a2+size_a3+size_a4 == size_max)){i++;printf(" %d:%d\t %d:%d\t %d:%d\t %d:%d\n",a1, size_a1,a2, size_a2,a3, size_a3,a4, size_a4);}	return i;
}

🚀四、并行搜索

⛳(一)并发的基本概念

所谓并发是在同一实体上的多个事件同时发生。并发编程是指在在同一台计算机上“同时”处理多个任务。要理解并发编程,我们必须要理解如下一些基本概念:

  1. 计算机就像一座工厂,时刻在运行,为人类服务。它的核心是 CPU,它承担了所有的计算任务,就像工厂的一个现场指挥官。

  2. 进程就像工厂里的车间,承担“工厂”里的各项具体的“生产任务”,通常每个进程对应一个在运行中的执行程序,比如,QQ 和微信运行的时候,他们分别是不同的进程。

  3. 因为特殊原因,现场指挥官人才短缺,整个工厂只有一个指挥官,一次只能指导一个车间生产,而所有的车间都必须要有现场指挥官在场才能生产。也就是说,一个车间开工的时候,其他车间都必须停工。

    背后的含义:任一时刻,单个 CPU 一次只能运行一个进程,此时其他进程处于非运行状态

    我们能同时运行QQ、微信,是因为速度非常快,这种机制叫做”时间片“

  4. 一个车间(进程)可以包括多条生产线,线程就好比车间(进程)里的生产线。所有生产线(设备和人)都属于同一车间的资源,受车间统一调度和调配,并共享车间所有资源(如空间或洗手间)。

    背后的含义:一个进程可以拥有多个线程,每个线程可以可以独立并行执行,多个线程共享同一进程的资源,受进程管理。

理解了以上这些概念后,我们接下来再继续讲解并行搜索的概念:假设我们要从很大的一个无序的数据集中进行搜索,假设我们的机器可以一次性容纳这么多数据。从理论上讲,对于无序数据,如果不考虑排序,已经很难从算法层面优化了。而利用上面我们提到的并行处理思想,我们可以很轻松地将检索效率提升多倍。

具体实现思路如下:

将数据分成 N 个块,每个块由一个 线程来并行搜索。

⛳(二)线程演示代码

#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <time.h>#define TEST_SIZE (1024*1024*200)
#define NUMBER 20DWORD WINAPI ThreadProc(void *lpParam){for(int i=0; i<5; i++){printf("进程老爸,我来了!\n");Sleep(1000);}return 0;
}int main(void){DWORD threadID1;//线程 1 的身份证HANDLE hThread1;//线程 1 的句柄DWORD threadID2;//线程 2 的身份证HANDLE hThread2;//线程 2 的句柄printf("创建线程... ... \n");//两个线程独立执行各自的函数后退出//创建线程 1hThread1 = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadID1);//创建线程 2//参数分别为:线程属性、线程堆栈的大小、线程启动后的执行函数、传递给线程函数的实参、线程标志、线程IDhThread2 = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadID2);//进程等待线程结束再继续执行,INFINITE表示时间无限大WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);printf("进程老爸欢迎线程归来!\n");system("pause");return 0;
}

拓展:完整示例代码:

#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <time.h>#define TEST_SIZE (1024*1024*200)
#define NUMBER 20typedef struct _search{int *data;//搜索的数据集size_t start; //搜索的开始位置size_t end; //搜索的终止位置size_t count; //搜索结果
}search;//检索代码
DWORD WINAPI ThreadProc(void *lpParam){search *s = (search*)lpParam;time_t start, end;printf("新的线程开始执行...\n");time(&start);for(int j=0; j<10; j++){ //外层延时循环for(size_t i=s->start; i<=s->end; i++){if(s->data[i] == NUMBER){s->count++;}}}time(&end);printf("查找数据所花时间: %lld\n", end-start);return 0;
}//并行代码(多线程)
int main02(void){int *data = NULL;int count = 0;//记录的数量int mid = 0;search s1, s2;data = new int[TEST_SIZE];for(int i=0; i<TEST_SIZE; i++){data[i] = i;}mid = TEST_SIZE/2;s1.data = data;s1.start = 0;s1.end = mid;s1.count = 0;s2.data = data;s2.start = mid+1;s2.end = TEST_SIZE-1;s2.count = 0;DWORD threadID1;//线程 1 的身份证HANDLE hThread1;//线程 1 的句柄DWORD threadID2;//线程 2 的身份证HANDLE hThread2;//线程 2 的句柄printf("创建线程... ... \n");//创建线程 1hThread1 = CreateThread(NULL, 0, ThreadProc, &s1, 0, &threadID1);//创建线程 2hThread2 = CreateThread(NULL, 0, ThreadProc, &s2, 0, &threadID2);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);printf("进程老爸欢迎线程归来!count: %d\n", s1.count+s2.count);system("pause");return 0;
}//串行代码
int main(void){int *data = NULL;int count = 0;//记录的数量data = new int[TEST_SIZE];for(int i=0; i<TEST_SIZE; i++){data[i] = i;}time_t start=0, end=0;//记录开始和结束的时间戳time(&start);for(int j=0; j<10; j++){for(int i=0; i<TEST_SIZE; i++){if(data[i] == NUMBER){count++;}}}time(&end);printf("查找数据所花时间: %lld, count: %d\n", end-start, count);system("pause");return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

行业追踪,2023-08-10

自动复盘 2023-08-10 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

关于MPU6050的VLOGIC引脚作用

关键字&#xff1a;MPU6X0X、 MPU6050、数字逻辑电平、VLOGIC 框图&#xff1a; 一、VLOGIC引脚作用? VLOGIC引脚主要用于设置为I2C供电引脚&#xff0c;以保证正确的I2C通信。 The bias and LDO section generates the internal supply and the reference voltages and cu…

轻松转换TS视频为MP4,实现优质视频剪辑体验

如果你是一个视频剪辑爱好者&#xff0c;你一定会遇到各种视频格式之间的转换问题&#xff0c;特别是将TS视频转换为MP4格式。别担心&#xff0c;我们的视频剪辑软件将为你提供最简单、高效的解决方案&#xff01; 首先第一步&#xff0c;我们要进入媒体梦工厂主页面&#xff…

Three.js 实现材质边缘通道发光效果

相关API的使用&#xff1a; 1. EffectComposer&#xff08;渲染后处理的通用框架&#xff0c;用于将多个渲染通道&#xff08;pass&#xff09;组合在一起创建特定的视觉效果&#xff09; 2. RenderPass(是用于渲染场景的通道。它将场景和相机作为输入&#xff0c;使用Three.…

【STM32】FreeRTOS消息队列和信号量学习

一、消息队列&#xff08;queue&#xff09; 队列是一种用于实现任务与任务之间&#xff0c;任务与中断之间消息交流的机制。 注意&#xff1a;1.数据的操作是FIFO模式。 2.队列需要明确数据的大小和队列的长度。 3.写和读都会出现堵塞。 实验&#xff1a;创建一个消息队列…

JAVA多线程和并发基础面试问答(翻译)

JAVA多线程和并发基础面试问答(翻译) java多线程面试问题 1. 进程和线程之间有什么不同&#xff1f; 一个进程是一个独立(self contained)的运行环境&#xff0c;它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序…

webpack中常见的Loader

目录 1.webpack中的loader是什么&#xff1f;配置方式 2. loader特性3.常见的loader 1.webpack中的loader是什么&#xff1f; loader 用于对模块的"源代码"进行转换&#xff0c;在 import 或"加载"模块时预处理文件 webpack做的事情&#xff0c;仅仅是分…

springboot 设置自定义启动banner背景图 教程

springboot banner Spring Boot中的banner是在应用程序启动时显示的一个ASCII艺术字符或文本。它被用来给用户展示一些关于应用程序的信息&#xff0c;例如名称、版本号或者公司标志等。 使用Spring Boot的默认设置&#xff0c;如果项目中有一个名为“banner.txt”的文件放置…

面试攻略,Java 基础面试 100 问(十一)

抽象类&#xff08;abstract class&#xff09;和接口&#xff08;interface&#xff09;有什么异同? 抽象类和接口都不能够实例化&#xff0c;但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现&#xff…

Cpp学习——vector模拟实现

vector简介 在模拟实现vector之前&#xff0c;首先就得知道vector是个啥&#xff1f;vector是个啥呢&#xff1f;vector是一个stl里面的容器&#xff0c;并且是一个模板容器。它就像是一个顺序表模板。还记得顺序表吧&#xff1f;之前我实现的顺序表只能弄整形的数据&#xff0…

微信小程序 map地图(轨迹)

allMarkers效果图 废话少说直接上马&#xff08;最后是我遇到的问题&#xff09; cover-view是气泡弹窗&#xff0c;可以自定义弹窗&#xff0c;要配合js&#xff1a;customCallout&#xff0c;如果是非自定义的话&#xff1a;callout&#xff08;可以修改颜色、边框宽度、圆角…

Ceph Reef版本 RBD 性能测试:80万写IOPS(10节点、60个NVMe SSD)

2023-05-16 08:30 发表于上海 摘自&#xff1a;https://mp.weixin.qq.com/s/mKkPElmCktoZaRk0m0IbqA 1、背景 Ceph 社区最近冻结了即将发布的 Ceph Reef 版本&#xff0c;今天我们研究一下 Ceph Reef 版本在 10 个节点、60 个 NVMe 磁盘的集群上的 RBD 性能。 在确保硬件没有…

医疗保健中的 NLP:实体链接

一、说明 HEalthcare和生命科学行业产生大量数据&#xff0c;这些数据是由合规性和监管要求&#xff0c;记录保存&#xff0c;研究论文等驱动的。但随着数据量的增加&#xff0c;搜索用于研究目的的必要文件和文章以及数据结构成为一个更加复杂和耗时的过程。例如&#xff0c;如…

小米平板6Max14即将发布:自研G1 电池管理芯片,支持33W反向快充

明天晚上7点&#xff08;8 月 14 日&#xff09;&#xff0c;雷军将进行年度演讲&#xff0c;重点探讨“成长”主题。与此同时&#xff0c;小米将推出一系列全新产品&#xff0c;其中包括备受瞩目的小米MIX Fold 3折叠屏手机和小米平板6 Max 14。近期&#xff0c;小米官方一直在…

MiniPaint:在线图像编辑利器【在线PS】

MiniPaint在线图像编辑器使用 HTML5 实现图像的在线创建与编辑&#xff0c;在线PS&#xff0c;支持超过40种效果滤镜&#xff0c;无需本地安装&#xff0c;在很多应用场景中可以替代PhotopShop等传统软件。 访问地址&#xff1a;MiniPaint - 在线PS - 在线图像编辑。 1、打开图…

词法分析器的设计与实现

1、实验目的及要求 1.1、实验目的 加深对词法分析器的工作过程的理解&#xff1b;加强对词法分析方法的掌握&#xff1b;能够采用一种编程语言实现简单的词法分析程序&#xff1b;能够使用自己编写的分析程序对简单的程序段进行词法分析。 1.2、实验要求 1&#xff09;对单词…

Towards Open World Object Detection【论文解析】

Towards Open World Object Detection 摘要1 介绍2 相关研究3 开放世界目标检测4 ORE:开放世界目标检测器4.1 对比聚类4.2 RPN自动标注未知类别4.3 基于能量的未知标识4.4 减少遗忘 5 实验5.1开放世界评估协议5.2 实现细节5.3 开放世界目标检测结果5.4 增量目标检测结果 6 讨论…

Postman

Postman 简介下载安装 简介 Postman 是一款用于测试和开发 API&#xff08;应用程序编程接口&#xff09;的工具&#xff0c;它提供了用户友好的界面和丰富的功能&#xff0c;帮助开发者轻松地创建、测试、调试和文档化各种类型的 API。无论是在构建 Web 应用、移动应用还是其…

2023.08.13 学习周报

文章目录 摘要文献阅读1.题目2.要点3.问题4.解决方案5.本文贡献6.方法6.1 特征选择6.2 时间序列平稳性检测与数据分解6.3 基于GRU神经网络的PM2.5浓度预测 7.实验7.1 网络参数7.2 实验结果7.3 对比实验 8.讨论9.结论10.展望 PINNS模型1.自动微分2.全连接神经网络3.PINNs模型的P…

优雅地处理RabbitMQ中的消息丢失

目录 一、异常处理 二、消息重试机制 三、错误日志记录 四、死信队列 五、监控与告警 优雅地处理RabbitMQ中的消息丢失对于构建可靠的消息系统至关重要。下面将介绍一些优雅处理消息丢失的方案&#xff0c;包括异常处理、重试机制、错误日志记录、死信队列和监控告警等。…