C++算法:排序、查找

news2025/3/9 10:43:42

排序

排序是一个非常经典的问题,它以一定的顺序对一个数组(或一个列表)中的项进行重新排序
有许多不同的排序算法,每个都有其自身的优点和局限性。

时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。

不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。

冒泡排序

  1. 比较相邻的元素。如果元素大小关系不正确,就交换它们两个;
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 重复步骤1~3,直到排序完成。

#pragma region 冒泡排序
/*
1.比较相邻的元素。如果元素大小关系不正确,就交换它们两个;
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对;
3.针对所有的元素重复以上的步骤,除了最后一个;
4.重复步骤1~3,直到排序完成。
*/
void BubbleSort1(int* arr, int size)
{
	for (int i = 0; i < size - 1;++i)
		for(int j=0;j<size-1-i;++j)
			if (arr[j]>arr[j + 1])
				std::swap(arr[j], arr[j + 1]);
}

void BubbleSort2(int* arr, int size)//改进版
{
	bool flag;
	for (int i = 0; i < size - 1; ++i)
	{
		flag = false;
		for (int j = 0; j < size - 1 - i; ++j)
		{
			if (arr[j]>arr[j + 1])
			{
				std::swap(arr[j], arr[j + 1]);
				flag = true;
			}
		}
		if (!flag)
			break; //如果没有发生交换,说明数组已经有序
	}
}

#pragma endregion 

快速排序

  1. 从待排序序列中挑出一个元素,作为”基准”;
  2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个过程叫分组或分区
  3. 递归地把”基准值前面的子数列”和”基准值后面的子数列”进行排序。不多于一个为止

#pragma region 快速排序
/*
1.从待排序序列中挑出一个元素,作为”基准”;
2.把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个过程叫分组或分区
3.递归地把”基准值前面的子数列”和”基准值后面的子数列”进行排序。不多于一个为止
*/


void QuickSort(int *arr, int start, int end)
{
	//分区
	if (start < end)
	{
		int i, j, p;
		i = start;
		j = end;
		p = arr[i];
		while (i < j)
		{
			while (i < j&& arr[i] < p)
				i++;  //从左往右找第一个大于p的数
			if (i < j)
				arr[j--] = arr[i];

			while (i<j&& arr[j]>p)
				j--;  //从右往左找第一个小于p的数

			if (i < j)
				arr[i++] = arr[j];
		}
		arr[i] = p;

		QuickSort(arr, start, i - 1);
		QuickSort(arr, i + 1, end);
	}
}
#pragma endregion 

插入排序

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

#pragma region 插入排序
void InsertSort(int* arr, int size)
{
	int temp;
	int j;
	for (int i = 1; i < size; ++i)
	{
		temp = arr[i];
		j = i - 1;
		while (j >= 0 && arr[j] > temp)
		{
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = temp;
	}
}

#pragma endregion 

桶排序

  1. 设置一个定量的数组当作空桶;
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序;
  4. 从不是空的桶里把排好序的数据拼接起来。
#pragma region 桶排序
void BucketSort(int* arr, int size, int max)
{
	//创建一个容量为max的数组buckets,并且将buckets中所有数据都初始化为0
	vector<int> buckets(max);
	//1.计数
	for (int i = 0; i < size; ++i)
		buckets[arr[i]]++;
	//2.排序
	for (int i = 0, j = 0; i < max; ++i)
	{
		while (buckets[i]>0)
		{
			arr[j] = i;
			j++;
			buckets[i]--;
		}
	}	
}

#pragma endregion 

希尔排序

  1. 对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;
  2. 对各组内的元素进行直接插入排序,这一趟排序完成之后,每一个组的元素都是有序的;
  3. 减小gap的值,并重复执行上述的分组和排序,当gap=1时,整个数列就是有序的。



#pragma region 希尔排序
//基于插入排序
void ShellSort(int* arr, int size)
{
	int temp;
	int j;
	//gap为步长 每次减为原来的一半
	for (int gap = size / 2; gap > 0; gap /= 2)
	{
		for (int i = gap; i < size; ++i)
		{
			temp = arr[i];
			j = i - gap;
			while (j >= 0 && arr[j] > temp)
			{
				arr[j + gap] = arr[j];
				j -= gap;
			}
			arr[j + gap] = temp;
		}
	}
}
#pragma endregion 

选择排序

  1. 未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;
  2. 从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排序序列的末尾;
  3. 以此类推,直到所有元素均排序完毕;

#pragma region 选择排序
void SelectionSort(int* arr, int size)
{
	for (int i = 0; i < size - 1; ++i)//有序区的末尾位置
	for (int j = i + 1; j < size; ++j)//无序区
	if (arr[i]>arr[j])
		swap(arr[i], arr[j]);
}
#pragma endregion 

归并排序

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序;
  3. 将两个排序好的子序列合并成一个最终的排序序列。


#pragma region 归并排序

void Merge(int* arr, int left, int mid, int right)
{
	int low = left;//左半部分起始位置   (low,mid)  
	int hight = mid + 1;//右半部分起始位置 (hight,right)
	int len = right - left + 1;
	vector<int> temp(len);//辅助数组
	int index = 0;//辅助数组下标

	while (low <= mid && hight <= right)
	{//挑选两部分最小的元素放到辅助数组中
		if (arr[low] < arr[hight])
		{
			temp[index] = arr[low];
			low++;
			index++;
		}
		else
		{
			temp[index] = arr[hight];
			hight++;
			index++;
		}
	}
	//剩余直接放到辅助数组中
	while (low <= mid)
	{
		temp[index] = arr[low];
		index++;
		low++;
	}
	while (hight <= right)
	{
		temp[index] = arr[hight];
		index++;
		hight++;
	}
	//更新原始左边的元素
	for (int i = 0; i < len; ++i)
	{
		arr[left + i] = temp[i];
	}
}

void MergeSort(int* arr, int left, int right)
{
	if (left < right)
	{
		int mid = (left + right) / 2; //分割
		MergeSort(arr, left, mid);	  //对左半部分进行归并
		MergeSort(arr, mid + 1, right);//对右半部分进行归并

		Merge(arr, left, mid, right);
	}
}
#pragma endregion 

查找

根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素

顺序查找

关键字与队列中的数从最后一个开始逐个比较,直到找出与给定关键字相同的数为止

#pragma region 顺序查找
int SequenceSearch(int* arr, int len, int val)
{
	for (int i = 0; i < len; ++i)
	{
		if (val == arr[i])
		{
			return i;
		}
	}
	return -1;
}

#pragma endregion 
  • 缺点:效率低下
  • 时间复杂度:最坏情况下,关键词比较次数为n+1,最好情况就是1,所以时间复杂度为O(logn)

二分查找

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。\

#pragma region 二分查找
int BinarySearch(int* arr, int val, int low, int high)
{
	int mid = (high + low) / 2;
	if (arr[mid] == val)
		return mid;
	if (arr[mid] > val)
		return BinarySearch(arr, val, low, mid - 1);
	if (arr[mid] < val)
		return BinarySearch(arr, val, mid + 1, high);
}

int BinarySearch1(int* arr, int val, int low, int high)
{
	int mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (arr[mid] == val)
			return mid;
		if (arr[mid] > val)
			high = mid - 1;
		if (arr[mid] < val)
			low = mid + 1;
	}
	return -1;
}

#pragma endregion 
  • 缺点:要求待查表为有序表
  • 时间复杂度:最坏情况下,关键词比较次数为,最好情况就是1,所以二分查找的时间复杂度为o(lob2n)

插值查找

基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率

#pragma region 插值查找
int InsertionSearch(int* arr, int val, int low, int high)
{
	//   arr[index]=val;
	//  (index-low)/ (val-arr[low])
	//=  (high-low)/(arr[high]-arr[low])

	int index = low + (val - arr[low]) / (arr[high] - arr[low]) *(high - low);
	if (arr[index] == val)
		return index;
	if (arr[index] > val)
		return BinarySearch(arr, val, low, index - 1);
	if (arr[index] < val)
		return BinarySearch(arr, val, index + 1, high);
}

#pragma endregion 

降序排序

//冒泡降序
void BubbleSort2(int* arr, int size)//改进版
{
	bool flag = false;
	for (int i = 0; i < size - 1; ++i)
	{
		flag = false;
		for (int j = 0; j < size - 1 - i; ++j)
		{
			if (arr[j] < arr[j + 1])
			{
				std::swap(arr[j], arr[j + 1]);
				flag = true;
			}
		}
		if (!flag)
			break;     // 若没发生交换,则说明数列已有序。
	}
}

//快速降序
void QuickSort(int* arr, int left, int right)
{
	if (left < right)
	{
		int i, j, p;
		i = left;
		j = right;
		p = arr[i];
		while (i < j)
		{
			while (i < j && arr[j] < p)
				j--; // 从右向左找第一个大于x的数
			if (i < j)
				arr[i++] = arr[j];
			while (i < j && arr[i] > p)
				i++; // 从左向右找第一个小于x的数
			if (i < j)
				arr[j--] = arr[i];
		}
		arr[i] = p;
		QuickSort(arr, left, i - 1); /* 递归调用 */
		QuickSort(arr, i + 1, right); /* 递归调用 */
	}
}
//插入降序
void InsertSort(int* arr, int size)
{
	int temp;
	int j;
	for (int i = 1; i < size; i++)
	{
		temp = arr[i];
		j = i - 1;
		while (j >= 0 && arr[j] < temp)
		{
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = temp;
	}
}
//桶排序降序
void BucketSort(int* arr, int size, int max)
{
	int i, j;
	// 创建一个容量为max的数组buckets,并且将buckets中的所有数据都初始化为0。
	vector<int> buckets(max);
	// 1. 计数
	for (i = 0; i < size; i++)
		buckets[arr[i]]++;
	// 2. 排序
	for (i = max - 1, j = 0; i >= 0; i--)
		while ((buckets[i]--) >0)
			arr[j++] = i;
}

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

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

相关文章

SQL之SQL优化

文章目录 一、插入数据优化insert优化大批量插入数据 二、主键优化数据组织方式页分裂页合并主键设计原则三、order by优化 四、Group By 优化五、limit优化六、count优化count的几种用法 七、update优化总结 一、插入数据优化 insert优化 insert into tb_test values(1, tom…

Linux:centos:系统服务基础控制(systemctl)基础使用 图形化工具ntsysv使用

基础使用的办法为&#xff1a; systemctl控制类型服务名称 控制常用类型为一下几个 start 启动 stop 停止 enable 开机自启 disable 开机不自启 restart 重新启动 reload 重新加载 status 查看服务状态 systemc…

Redis---主从复制

一、redis主从复制 主从复制&#xff1a;是存储数据的服务结构 主服务器&#xff1a;接受客户端连接的服务器 从服务器&#xff1a;自动与主服务器保持数据一致的服务器 配置主从复制 1、环境准备 主服务器 主机名&#xff1a;master IP地址&#xff1a;192.168.11.101/…

在PyCharm中配置Git

防止以后换软件或电脑忘记怎么配置PyCharm&#xff0c;记录一下。 前提 电脑已经安装好了Git工具&#xff0c;安装教程有一个GitHub账号&#xff08;这不废话嘛…&#xff09;电脑最好有科学上网工具&#xff08;要不然拉取、推送等操作总是不成功&#xff09; PyCharm设置 …

VMware安装苹果系统教程 MAC安装VMware Tools,开启拖拽功能

VMware虚拟机安装苹果系统教程 1 准备工作 安装VM虚拟机、准备Install_macOS_Monterey_12.5 镜像、darwin1012.iso &#xff08;VMware Tools&#xff09;、unlocker解锁工具 2 解锁VM虚拟机 默认VM虚拟机是不支持macOS安装的&#xff0c;我们需要对虚拟机进行解锁操作&…

5.java程序员必知必会类库之excel读写库

前言 Excel在数据处理中的重要性自不必说&#xff0c;我们经常会有需求&#xff0c;将数据库中的数据&#xff0c;做过一些处理后&#xff0c;导出一个Excel给运营人员分析。也有需求是将批量的商品数据等&#xff0c;批量录入到我们系统中。直观上可以理解为Excel是客户和系统…

ASP 、PHP 代码加密的安全性逻辑思考

以古董后台语言 asp 为例&#xff0c;为了保证明文代码不被最终使用者修改或抄袭&#xff0c;有多种方法对代码进行编码&#xff0c;执行时再解码。也可以直接将代码全部编译入 COM 组件 &#xff0c;但是这需要每次都编译&#xff0c;不适合日常使用。 因此&#xff0c;这里考…

【STL十二】适配器——容器适配器

【STL十二】适配器——容器适配器 一、适配器1、适配器简介2、使用适配器的优点3、适配器种类3.1、容器适配器3.2、迭代器适配器3.3、函数适配器&#xff08;function adapters) 二、容器适配器1、简介2、分类 三、stack适配器1、简介2、构造函数3、成员函数4、demo 三、queue适…

Ubuntu NVIDIA-Docker安装

Ubuntu NVIDIA-Docker安装 Docker简介NVIDIA驱动安装NVIDIA-Docker安装 系统环境&#xff1a; 系统&#xff1a;linux 版本&#xff1a;ubuntu20.04 Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#…

WebRTC真实IP泄露

WebRTC真实IP泄露 1.概述2.利用漏洞获取真实IP地址演示3.WebRTC介绍4.WebRTC 泄漏真实IP原理5.防范措施 1.概述 很多人可能误以为使用代理就可以完全隐藏我们的真实IP地址&#xff0c;但实际并不总是这样。事实上&#xff0c;有大量文章指出&#xff0c;WebRTC存在安全风险&am…

零项目零科研,本科排名倒数,一战上岸上海交大电子与通信工程

笔者来自通信考研小马哥23上交819全程班学员 本科就读于哈工大&#xff08;威海&#xff09;&#xff0c;本科成绩很差&#xff0c;专业排名62/99&#xff0c;没有科研&#xff0c;没有实验室&#xff0c;没有项目&#xff0c;连最基本大家都会参加的科技立项我四年也没有参与…

幽灵空白节点

图片下面为什么会有空白间隙呢&#xff1f;因为内联元素默认都是和 a 的下边缘基线对齐&#xff0c;基线和底部是有一段距离的&#xff0c;所以图片下面有一段间隙。 <style>.container {background-color: red;}img {width: 100px;height: 100px;} </style><d…

误删恢复及备份恢复

误删恢复&#xff0c;及备份恢复 一、误删恢复1.1用losf恢复进程存在的文件1.2恢复EXT类型的文件 二、备份恢复的集中方式2.1用xfsdump&#xff0c;xfsrestore对xfs类型文件进行备份恢复2.2用cpio命令备份恢复2.2.1通过find过滤文件进行备份 一、误删恢复 1.1用losf恢复进程存…

自然语言处理实战项目4-文本相似度的搜索功能,搜索文本内容

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来自然语言处理实战项目4-文本相似度的搜索功能&#xff0c;搜索文本内容。文本相似度搜索是一种基于自然语言处理技术&#xff0c;用于搜索和匹配文本内容的方法。其主要目的是将用户输入的查询内容与已有的文本数据进行…

c盘满了怎么清理垃圾而不误删?C盘清理,4个方法!

案例&#xff1a;c盘满了怎么清理垃圾而不误删 【我的c盘现在已经爆红了&#xff01;想清理下c盘的文件&#xff0c;但是害怕误删重要的文件&#xff0c;应该怎么做才能清理c盘但不误删重要的文件呀&#xff01;急需答案&#xff01;】 随着时间的推移&#xff0c;c盘可能会因…

游戏服务器如何搭建

无论是游戏公司还是游戏爱好者&#xff0c;游戏服务器都是不可或缺的一部分。游戏服务器承载着游戏的运行和体验&#xff0c;是在所有玩家之间建立连接的纽带。如果你想了解如何搭建游戏服务器以及相关的配置要求&#xff0c;那么本文是无法错过的。在本文中小编将为您介绍如何…

Nginx安装注意事项

一.看你是什么系统,先从官网下载你想要的版本 二.windows系统 直接解压就行了 conf 是放配置文件的地方 html是 放页面的位置 ,欢迎页也在这里 有什么静态资源也可以放这里 logs 放日志文件 在路径栏位置直接cmd 开启命令窗口 注意这里是在nginx.exe文件所在目录进行的…

TOOM解析如何搭建一套适合自己的舆情监测系统?完整的实战指南

随着互联网的普及和社交媒体的盛行&#xff0c;人们在网络上的活动越来越多&#xff0c;同时也涌现出大量的信息和舆情。这些信息和舆情在一定程度上会影响社会和个人的发展和进步。因此&#xff0c;舆情监测逐渐成为一项重要的任务。在本篇文章中&#xff0c;我们将为大家介绍…

Adobe国际认证中文官网

Adobe国际认证中文官网是Adobe公司为了帮助用户提高技能水平和职业竞争力而推出的认证服务。该官网提供了一系列的Adobe认证考试&#xff0c;包括Photoshop、Illustrator、InDesign、Premiere Pro等多个软件的认证考试。通过参加这些考试&#xff0c;用户可以获得Adobe认证&…

ASEMI代理ADG5412BRUZ-REEL7原装ADI车规级ADG5412BRUZ-REEL7

编辑&#xff1a;ll ASEMI代理ADG5412BRUZ-REEL7原装ADI车规级ADG5412BRUZ-REEL7 型号&#xff1a;ADG5412BRUZ-REEL7 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;TSSOP-16 批号&#xff1a;2023 引脚数量&#xff1a;5 安装类型&#xff1a;表面贴装型 ADG5412BRUZ-…