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

news2024/11/26 22:41:35

文章目录

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


🚀一、预备知识

⛳(一)查找的定义

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

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

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

查找操作及分类:

  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);
		else
			return 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 20

DWORD 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");
    
    //两个线程独立执行各自的函数后退出
    //创建线程 1
    hThread1 = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadID1);
    
    //创建线程 2
    //参数分别为:线程属性、线程堆栈的大小、线程启动后的执行函数、传递给线程函数的实参、线程标志、线程ID
    hThread2 = 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 20

typedef 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");
    //创建线程 1
    hThread1 = CreateThread(NULL, 0, ThreadProc, &s1, 0, &threadID1);
    //创建线程 2
    hThread2 = 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.coloradmin.cn/o/872169.html

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

相关文章

修改VS Code终端的显示行数

文章目录 前言修改VS Code终端显示行数参考 前言 在我们使用VS Code运行代码的过程中&#xff0c;有时需要再终端中显示很多的运行过程信息或者结果。然而&#xff0c;VS Code的终端默认显示1000行的内容&#xff0c;随着显示内容的增多&#xff0c;之前的内容就丢失了。为了解…

【单片机毕业设计2-基于stm32c8t6的智能台灯系统】

【单片机毕业设计2-基于stm32c8t6的智能台灯系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇2 基于stm32的智能台灯系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖 企鹅号&#xff1a;2836235214 一、功…

Java IO流——【从零构建信息管理系统】

Java I/O流——【从零构建信息管理系统】 文章目录 什么是Java I/O流介绍理解字节流和字符流的区别 Java I/O流的作用Java I/O流方法InputStream方法Reader方法OutputStream方法Writer方法Java I/O体系的全体类 使用示例Java I/O流在实际应用中使用效果 什么是Java I/O流 介绍…

多线程事务怎么回滚?

项目中用到了多线程去批量处理一些数据&#xff0c;当时想当然认为只要方法上加上Transactional注解就好了&#xff0c;实际并未达到想要的处理效果。特此去学习了下关于多线程事务回滚相关方案&#xff0c;参考了网上其他资料&#xff0c;这里整理并记录下学习历程。 站在巨人…

在 IntelliJ IDEA 中使用 Docker 开发指南

目录 一、IDEA安装Docker插件 二、IDEA连接Docker 1、Docker for Windows 连接 2、SSH 连接 3、Connection successful 连接成功 三、查看Docker面板 四、使用插件生成镜像 一、IDEA安装Docker插件 打开 IntelliJ IDEA&#xff0c;点击菜单栏中的 "File" -&g…

山西电力市场日前价格预测【2023-08-14】

日前价格预测 预测明日&#xff08;2023-08-14&#xff09;山西电力市场全天平均日前电价为322.03元/MWh。其中&#xff0c;最高日前电价为366.98元/MWh&#xff0c;预计出现在19: 30。最低日前电价为286.57元/MWh&#xff0c;预计出现在13: 15。 价差方向预测 1&#xff1a; 实…

腾讯出了一个新聊天软件M8

众所周知&#xff0c;如今国内互联网&#xff0c;微信和QQ无疑是社交领域的霸主。 下载:https://www.123pan.com/s/BP5A-RW4xh.html 不过&#xff0c;它们也有各自局限性&#xff0c;比如难以结识新朋友、功能过于复杂等。 这让用户产生厌倦&#xff0c;再加上近几年AI、元宇…

标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

SCSS的基本用法

1、声明变量 $ 声明变量的符号 $ 下面这张图左半部分是scss的语法&#xff0c;右半部分是编译后的css。&#xff08;整篇文章皆是如此&#xff09; 2、默认变量 !default sass 的默认变量仅需要在值后面加上 !default 即可。 如果分配给变量的值后面添加了 !default 标志…

jmeter通过BeanShell对接口参数进行MD5和HmacSHA256加密【杭州多测师_王sir】

一、在eclipse里面编写MD5加密算法 package com.Base64;import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;public class Md5Utils {public static String md5(String sourceStr) {String result "";try {MessageDigest md Mess…

教你10分钟内学习如何CSS 设置网页打印时的样式

本文将教您开始为要打印的页面编写CSS所需要的一切提供帮助。 media 规则 If you’ve done any responsive design, you’ll already know about the media rule. As well as different screen sizes, media also lets you target “print” media. Here’s an example: 如果…

【CTF-web】修改请求头(XFF)

题目链接&#xff1a;https://ctf.bugku.com/challenges/detail/id/79.html 随意输入后可以看到需要本地管理员登录&#xff0c;得知这是一道需要修改XFF头的题。 XFF即X-Forwarded-For&#xff0c;该请求标头是一个事实上的用于标识通过代理服务器连接到 web 服务器的客户端的…

腾讯轻量云服务器搭建Node.js开发环境

1.购买腾讯云轻量应用服务器&#xff0c;登录 轻量应用服务器控制台&#xff0c;在 服务器 页面单击 新建。安装运行环境&#xff0c;选择为应用模板 > Web 开发场景 > Node.js 应用模板。 Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境&#xff0c;基于 Chrome V…

分布式文件存储系统-FastDFS

前言&#xff1a;FastDFS 是一个分布式文件存储系统&#xff0c;主要用于存储和管理大规模的文件数据&#xff0c;如图片、视频、文档等&#xff0c;是淘宝前架构师为了存储图片用C语言开发出来的系统。 服务端有两个组件 Tracker Server 与 Storage Server &#xff0c;对应两…

​API网关类型与区别​

什么是API网关&#xff1f; 在现代软件架构中&#xff0c;API&#xff08;应用程序编程接口&#xff09;网关起着重要的作用。它是一个中间层&#xff0c;用于管理和控制应用程序之间的通信。API网关可以提供一些关键功能&#xff0c;如流量控制&#xff0c;安全认证&#xff…

java项目打包运行报异常:Demo-1.0-SNAPSHOT.jar中没有主清单属性

检查后发现pom文件中有错误&#xff0c;需要添加build内容才能恢复正常。 添加下面文件后再次启动恢复正常。 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactI…

Docker安装nacos v2.1.1

目录 前言安装nacos安装步骤1&#xff1a;准备1. 安装docker2. 搜索可以使用的镜像。3. 选择合适的redis镜像。3. 也可从docker hub上搜索镜像。 安装步骤2&#xff1a;拉取镜像拉取镜像查看已拉取的镜像 安装步骤3&#xff1a;创建容器创建容器方式1&#xff1a;快速创建容器创…

C语言实现扫雷游戏(附完整代码)

大家好&#xff0c;欢迎来到Mr.kanglong的CSDN博客&#xff0c;这篇博客来讨论一下如何使用C语言实现扫雷游戏&#xff0c;其实扫雷游戏和我之前写的三子棋游戏大体实现框架一样&#xff0c;只是逻辑有所不同。 目录 扫雷游戏介绍 游戏效果 实现代码 game.c game.h test.c 扫…

React学习之路 - 上传代码到GitCode

Git 全局设置 git config --global user.name "AnyaPapa" git config --global user.email "fangtaihongqq.com" 添加SSH密钥 Mac终端输入命令 cd existing_folder git init git remote add origin gitgitcode.net:Java_1710/test.git git add . git com…

msvcr120.dll丢失怎样修复?总结三个dll修复方法

当我遇到msvcr120.dll丢失的问题时&#xff0c;我感到有些困惑和焦虑。因为这个问题会导致我无法运行依赖这个文件的应用程序。msvcr120.dll是运行时库文件的一部分&#xff0c;为应用程序提供了必要的运行时支持。它的丢失会导致应用程序无法正常运行&#xff0c;这让我意识到…