数据结构排序:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序

news2025/3/1 2:53:02

文章目录

  • 插入排序
  • 希尔排序
  • 选择排序
  • 冒泡排序
  • 堆排序
  • 快速排序


插入排序

  1. 基本思想: 直接插入排序是一种简单的插入排序法,其基本思想是: 把待排序的值按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
  2. 直接插入排序: 当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与 array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

image

实现:

//插入排序
void InsertSort(int* a,int n) {

	for (int i = 0; i < n - 1;i++) {
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0) {
			if (tmp < a[end]) {
				a[end + 1] = a[end];
				--end;
			}
			else {
				break;
			}
		}
		a[end + 1] = tmp;
	}

}

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高

  2. 时间复杂度:O(N^2)

  3. 空间复杂度:O(1),它是一种稳定的排序算法

  4. 稳定性:稳定

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有记录按gap分成若干个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后缩小gap的值,重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序(当gap=1时其实就是直接插入排序)。

注:希尔排序就是先对待排数组进行一次预排序,将数组变的尽量接近有序,再使用直接插入排序进行最终排序

image

实现:

//希尔排序
void ShellSort(int* a,int n) {
	int gap = n;

	while (gap > 1) {

		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++) {
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0) {
				if (a[end] > tmp) {
					a[end + gap] = a[end];
					end -= gap;
				}
				else {
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}

}

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。

  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的 希尔排序的时间复杂度都不固定

  4. 稳定性:不稳定

选择排序

直接选择排序:

  • 在元素集合array[i]–array[n-1]中选择关键码最大和最小的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

image实现:

//选择排序
void SelectSort(int* a,int n) {

	int min = 0;
	int max = n - 1;
	while (min <= max) {
		int min1 = min;
		int max1 = max;
		for (int i = min; i <= max;i++) {
			if (a[min1] > a[i]) {
				min1 = i;
			}
			if (a[max1] < a[i]) {
				max1 = i;
			}
		}
		Swap(&a[min],&a[min1]);
		if (max1 == min) {
			Swap(&a[max],&a[min1]);
		}
		Swap(&a[max],&a[max1]);
		min++;
		max--;
	}

}

直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

  2. 时间复杂度:O(N^2)

  3. 空间复杂度:O(1)

  4. 稳定性:不稳定

冒泡排序

左边大于右边交换一趟排下来最大的在右边

实现:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//冒泡排序
void BubbleSort(int* a,int n) {

	for (int i = n; i > 0;i--) {
		for (int j = 0; j < i - 1; j++) {
			if (a[j] > a[j + 1]) {
				Swap(&a[j],&a[j +1 ]);
			}
		}
	}

}

冒泡排序的特性总结:

  1. 冒泡排序是一种非常容易理解的排序

  2. 时间复杂度:O(N^2)

  3. 空间复杂度:O(1)

  4. 稳定性:稳定

堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。

先使用数据进行建堆,在升序排列中,建立一个大堆,建好后最大的数据在最上面,然后将最上面的数据a[0],与最后位置的数据a[n-1]进行调换,这样a[n-1]位置的数据就是最大的了,最大数据就在了最后面;在对剩下的位置的数据进行调整,再调整为一个大堆,再将a[0](现在是第二大的数据)与a[n-2]的数据进行调换,这样第二大的数据就砸倒数第二个位置上;后面以次类推,直到堆中仅剩一个数据,排序完成。

需要注意的是排升序要建大堆,排降序建小堆。

对于堆不了解的可以去看我的树与二叉树这一篇文章

实现:

void HeapSort(int* a, int n) {
	//向下调整建小堆
	for (int i = (n - 1 - 1) / 2; i >= 0;i--) {
		AdjustDown(a,n,i);
	}

	int end = n - 1;
	while (end > 0) {
		Swap(&a[0],&a[end]);
		AdjustDown(a,end,0);
		end--;
	}
}

堆排序的特性总结:

  1. 堆排序使用堆来选数,效率就高了很多。

  2. 时间复杂度:O(N*logN)

  3. 空间复杂度:O(1)

  4. 稳定性:不稳定

快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,

其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

// 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{
 if(right - left <= 1)
 return;

 // 按照基准值对array数组的 [left, right)区间中的元素进行划分
 int div = partion(array, left, right);

 // 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
 // 递归排[left, div)
 QuickSort(array, left, div);

 // 递归排[div+1, right)
 QuickSort(array, div+1, right);
}

上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,同学们在写递归框架时可想想二叉 树前序遍历规则即可快速写出来,后序只需分析如何按照基准值来对区间中数据进行划分的方式即可。

实现:

//快排
void QuickSort(int* a,int begin,int end) {
	if (begin >= end) {
		return;
	}
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int left = begin, right = end;
	int key = begin;
	while (left < right) {
		//右边找小值
		while (left < right && a[right] >= a[left]) {
			right--;
		}
		//左边找大值
		while (left < right && a[left] <= a[key]) {
			left++;
		}
		//如果数组有序,找不到位置,那么此时就会左右相等,不进行交换
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left],&a[key]);
	key = left;

	QuickSort(a,begin,key-1);
	QuickSort(a,key+1,end);
}

改进版:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

int PartSort1(int* a, int begin, int end)
{
	int mid = GetMid(a, begin, end);
	Swap(&a[mid], &a[begin]);

	int left = begin, right = end;
	int keyi = begin;

	if (end - begin + 1 < 10) {
		InsertSort(a+begin,end - begin + 1);
	}

	while (left < right)
	{
		// 右边找小
		while (left < right && a[right] >= a[keyi])
		{
			--right;
		}

		// 左边找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}

		Swap(&a[left], &a[right]);
	}

	Swap(&a[left], &a[keyi]);

	return left;
}

挖坑法:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

//挖坑法块排
int PartSort2(int* a,int begin,int end) {
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int key = a[begin];
	int hole = begin;
	while (begin < end) {
		//右边找小值
		while (begin < end && a[end] >= key) {
			end--;
		}
		a[hole] = a[end];
		hole = end;
		//左边找大值
		while (begin < end && a[begin] <= key) {
			begin++;
		}
		a[hole] = a[begin];
		hole = begin;
	}

	a[hole] = key;
	return hole;
}

前后指针法:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

//前后指针
int PartSort3(int* a, int begin, int end) {
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int pre = begin, cur = begin + 1;
	int key = begin;
	while (cur <= end) {
		//cur找小值
		if (a[cur] <= a[key] && ++pre != cur) {
			Swap(&a[pre], &a[cur]);
		}
		cur++;

	}
	Swap(&a[pre], &a[key]);

	return pre;
}

快速排序的特性总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

  2. 时间复杂度:O(N*logN)

  3. 空间复杂度:O(logN)

  4. 稳定性:不稳定

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

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

相关文章

matlab入门,在线编辑,无需安装matab

matlab相关教程做的很完善&#xff0c;除了B站看看教程&#xff0c;官方教程我觉得更加高效。跟着教程一步一步编辑&#xff0c;非常方便。 阅读 MATLAB 官方教程&#xff1a; MATLAB 官方教程提供了从基础到高级的教学内容&#xff0c;内容包括 MATLAB 的基本语法、数据处理…

AUTOSAR CP--chapter7从CAN网络学习Autosar通信

从CAN网络学习Autosar通信 前言缩写词CAN通信在AUTOSAR架构中的传输上位机配置 第六章总结&#xff1a;学习了如何使用工具的自动配置功能&#xff0c;位我们生成系统描述中部分ecu的BSW模块配置&#xff0c;但是自动配置的功能虽然为我们提供了极大的便利&#xff0c;我们仍然…

Windows 使设置更改立即生效——并行发送广播消息

目录 前言 1 遍历窗口句柄列表 2 使用 SendMessageTimeout 发送延时消息 3 并行发送消息实现模拟广播消息 4 修改 UIPI 消息过滤器设置 5 托盘图标刷新的处理 6 完整代码和测试 本文属于原创文章&#xff0c;转载请注明出处&#xff1a; https://blog.csdn.net/qq_5907…

运筹系列89:anylogic仿真软件入门

1. agent-based simulation 这里概述一下help文档中Supply chain GIS model例子的要点&#xff1a;触发事件的agent和执行任务的agent。 在这个案例中&#xff0c;触发事件的agent是retailer&#xff0c;不断有订单生成&#xff1b;而执行任务的agent是vehicle&#xff0c;不断…

成功解决:× python setup.py egg_info did not run successfully.

执行pip install -r requirements.txt报错 错误信息如下&#xff1a; error: subprocess-exited-with-error python setup.py egg_info did not run successfully.│ exit code: 1╰─> [93 lines of output]解决办法&#xff1a; 更新 setuptools 和 pip pip install -…

比特浏览器bit_selenium3bit_selenium4使用

bit_selenium3 from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.options import Options from bit_api import *# /browser/open 接口会返回 selen…

我不允许你还不知道!这些求职常用黑话!

我不允许你还不知道&#xff01;这些求职常用黑话&#xff01; 一. HC、BG、BU、JD、OD、OT&#xff08;公司相关&#xff09;二、岗位相关1、base2、JD3、RD4、QA5、PM6、PR7、PD 三、求职或者薪资1、OC/意向书2、开奖3、泡池子4、保温5、A&#xff08;argue&#xff09;6、总…

数据库的备份模式(完全备份,增量备份,差异备份)

数据库的备份 备份原因 数据的丢失 数据的删除 备份目标 数据的一致性 数据的可用性 备份技术 物理备份/冷备份 直接复制数据库文件&#xff0c;适用于大型数据库环境&#xff0c;不受存储引擎的限制&#xff0c;但不能恢复到不同的MySQL版本。 常用的冷备份工具 ta…

电阻负载柜是什么?

电阻负载柜是用于模拟实际负载的设备&#xff0c;主要用于电力系统、电气设备和电子设备的测试、调试和维护。它通过调节电阻值来改变负载的大小&#xff0c;以满足不同场合的需求。电阻负载柜在电力系统、电气设备和电子设备的测试、调试和维护过程中发挥着重要作用。 电阻负载…

BI 数据分析,数据库,Office,可视化,数据仓库

AIGC ChatGPT 职场案例 AI 绘画 与 短视频制作 PowerBI 商业智能 68集 Mysql 8.0 54集 Oracle 21C 142集 Office 2021实战应用 Python 数据分析实战&#xff0c; ETL Informatica 数据仓库案例实战 51集 Excel 2021实操 100集&#xff0c; Excel 2021函数大全 80集 Excel 2021…

外贸人大部分都复工了吧

这几天是属于国家规定的节后上班时间&#xff0c;估计大部分人都已经开始复工了。作为粤西地区小伙伴中的一员&#xff0c;表示虽然身在广州&#xff0c;心却还在高州&#xff0c;毕竟年例在这些天才刚刚开始&#xff0c;我们那边每年最热闹的时候就是年例了&#xff01; 由于…

XCharts——Unity上最好用的免费开源图表插件!(一)基本介绍

只讲实用干货&#xff01;&#xff01;&#xff01;&#xff08;过于细节的或是未提及到的可直接问&#xff09; 目录 XCharts介绍 插件简介 插件下载 XCharts基本使用 类型介绍 1.折线图&#xff08;LineChart&#xff09; 2.柱形图&#xff08;BarChart&#xff09; …

IBM Spectrum LSF Process Manager 在共享分布式计算环境中运行和管理业务关键工作流程

IBM Spectrum LSF Process Manager 设计、记录和运行复杂的计算工作流 亮点 ● 快速创建复杂的分布式工作流 ● 开发可重复的最佳实践 ● 自信地运行关键工作流程 ● 提高流程可靠性 IBM Spectrum LSF Process Manager 使您能够设计和自动化计算或分析流程&#xff0c; 捕获…

力扣(LeetCode)数据结构练习题(2)

今天又写了两道关于链表的练习题&#xff0c;来给大家分享一下。巩固一下上一篇学到的链表知识&#xff0c;题目可以然我们更清楚的认识链表。 目录 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 给你单链表的头结点 head &#xff0c;请…

论文阅读-基于动态权重的一致性哈希微服务负载均衡优化

论文名称&#xff1a;基于动态权重的一致性哈希微服务负载均衡优化 摘要 随着互联网技术的发展&#xff0c;互联网服务器集群的负载能力正面临前所未有的挑战。在这样的背景下&#xff0c;实现合理的负载均衡策略变得尤为重要。为了达到最佳的效率&#xff0c;可以利用一致性…

从理论到实践:车间精益生产培训的全面应用指南

精益生产培训在车间的应用通常会通过以下几个步骤进行实践&#xff1a; 理论培训&#xff1a;首先&#xff0c;需要对车间的员工进行精益生产的基本理论培训&#xff0c;让他们理解精益生产的核心理念&#xff0c;比如价值流、流程优化、减少浪费、持续改进等。 现场诊断&am…

刚开工,就用Python兼职赚了5w!

前言 今天是节后上班第一天&#xff0c;祝大家开工大吉&#xff01; 先说个好消息&#xff1a;每年春节后&#xff0c;会迎来Python圈内兼职接单的小高潮。近期可以很轻松地&#xff0c;接到爬虫类和数据分析类的私活&#xff0c;需求大报酬高。 往年春节开工后的几天&#…

Spring Boot与LiteFlow:轻量级流程引擎的集成与应用含完整过程

点击下载《Spring Boot与LiteFlow&#xff1a;轻量级流程引擎的集成与应用含完整过程》 1. 前言 本文旨在介绍Spring Boot与LiteFlow的集成方法&#xff0c;详细阐述LiteFlow的原理、使用流程、步骤以及代码注释。通过本文&#xff0c;读者将能够了解LiteFlow的特点&#xff…

鸿蒙原生应用元服务实战-Serverless华为账户认证登录需尽快适配

一、ArkTS\API9&#xff0c;服务器端基于serverless开发的应用与元服务华为账号注册登录功能暂时是不支持的 二、3月1日后的审核要求 3月1日的时间是快到了。 三、会导致的结果 使用了ArkTS\API9&#xff0c;服务器端基于serverless开发的应用与元服务&#xff0c;如果要…

devc++跑酷小游戏底层讲解

以3.0.0为例 采集按键&#xff1a; 我们需要一个函数来采集用户按下的按键以便我们执行相应的代码&#xff0c;不能有回显&#xff08;输入的字符会显示在控制台程序上&#xff09;&#xff0c;不用回车也可以读取到 cin&#xff0c;scanf&#xff1a; 输入的类型为char&am…