数据结构---八大排序

news2025/1/23 7:50:09

专栏:算法
个人主页:HaiFan.
本章内容为大家带来排序的相关内容,希望大家能多多支持。

八大排序

  • 前言
  • 插入排序
    • 直接插入排序
    • 希尔排序(缩小增量排序)
  • 选择排序
    • 选择排序
    • 堆排序
  • 交换排序
    • 冒泡排序
    • 快速排序
      • hoare版
      • 挖坑版
      • 前后指针法
  • 归并排序

前言

排序在日常生活十分的重要,买一个东西的时候,肯定要看价格;打游戏的时候的段位排名;游戏下载次数的排行等等,都需要用到排序,下面,HaiFan来为大家介绍一下常用的排序方法。

插入排序:直接插入排序和希尔排序

选择排序:选择排序:堆排序

交换排序:冒泡和快排

归并排序:归并

计数排序

插入排序

直接插入排序是一种最简单的排序方法,将一条记录插入到已排好的有序表中,从而完成排序。

直接插入排序

在这里插入图片描述

在这里以升序为例

  1. 每次都先将一个待排序的元素(tmp)给记录下来
  2. 依次与tmp之前的元素进行比较
  3. 如果a[i] > tmp,则让a[i]向后移动;若a[i] < tmp,说明找到了合适的位置,直接让tmp插入这个位置即可
  4. 重复1,2,3的操作,直到元素排序完成

下面是代码实现

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 (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

值得注意的是,for循环里的n - 1,如果换成n就会造成越界访问。

希尔排序(缩小增量排序)

希尔排序是在直接插入排序的基础上做了改进,使得排序效率更高。

希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

来源—百科

1.我觉得这个排序方法更像分组排序,先把一个序列分成n个小组,

在这里插入图片描述

2.小组的第一个依次排序,每组的第二个依次排序…,排完之后,该序列会变成一个接近有序的序列

在这里插入图片描述

3.然后继续分组,把组进行细分,然后执行2的步骤,直到变成一个元素一组。此时序列就会变得有序

当gap大于1的时候,都是预排序,让序列接近有序,当gap==1的时候,因为序列已经接近有序,这个时候排序就会非常的块,


代码如下

void ShellSort(int* a, int n)
{
	int gap = n;//表示分成几组

	while (gap > 1)
	{
		gap /= 2;//每次分组都/2

		for (int i = 0; i < n - gap; i += gap)
		{
			int end = i;
			int tmp = end + gap;//直接插入排序的tmp是end的下一个元素,tmp和tmp之前的元素进行比较;而希尔排序的tmp是下一组的第一个元素,end是本组的第一个元素,组与组之间进行交换
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

选择排序

选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

来源–百科

请添加图片描述

这个排序挺直观的,两层for循环即可搞定。

以升序为例

1.第一层循环(变量i表示循环中的变量)用来表示需要交换的位置,我们要升序排列,第一个元素肯定要是最小的,而第一层for循环控制的就是位置,将最小的元素放入第一个位置里

2.第二层循环用来遍历序列,当然是从i+1开始遍历的,因为本身不需要遍历,遇到比a[i]小的,就交换

3.重复的执行1和2,直到遍历完


代码如下

void SelectSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			if (a[i] < a[j])
			{
				swap(a[i], a[j]);
			}
		}
	}
}

堆排序

堆排序嘛,肯定要先建立一个堆,这里我们可以选择向上或者向下建堆的方式,本文是以向下建堆为例。建堆是有要求的,左右子树都要是大根堆或者小根堆,这样在建堆的过程中,才不会乱。

在向下建堆的时候,我们要从哪一棵子树开始呢?

在这里插入图片描述

建堆的目的是使每棵子树都是大根堆或者小根堆的状态,所以我们要找一个能把所有子树都包含的位置,也就是下标为3的位置(根的下标为0,4的下标为2),这样就能完成建堆。

在这里插入图片描述

以这个图为例,讲解一下建堆(大根堆)的过程。

1.找到最后一个非叶子节点:因为堆的定义是一棵完全二叉树,因此最后一个节点的父节点就是最后一个非叶子节点。

2.从最后一个非叶子节点开始,逐个向下调整节点,使得以该节点为根节点的树满足堆的性质,当然建堆的时候,需要注意跟左右孩子进行比较,选出最大的那个孩子和父节点进行比较。

3.重复2操作,直至堆中所有节点都满足堆的性质,此时堆就构建完成了。

4.堆排序就是将堆顶元素与堆的最后一个元素进行交换,然后向下调整堆,并且总元素个数减1.


代码如下;

void JustDown(int* a, int parent, int s)
{
	int child = parent * 2 + 1;

	while (child < s)
	{
		if (child + 1 < s && a[child] < a[child + 1])
		{
			child++;
		}

		if (a[child] > a[parent])
		{
			swap(a[child], a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* a, int n)
{
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		JustDown(a, i, n);
	}

	int end = n - 1;

	while (end > 0)
	{
		swap(a[end], a[0]);
		JustDown(a,0,end);
		--end;
	}


}

交换排序

冒泡排序

冒泡排序:就是将两个相邻的元素进行比较,每次确定一个最值,然后得到有序序列。

冒泡跟选择一样,两个for循环就能搞定,每次循环都能确定一个最值,并将最值移动到数组的最后一个位置,然后第二次循环的时候,就不会在对最后一个位置进行比较。
在这里插入图片描述


代码如下

void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - i - 1; j++)
		{
			if (a[j + 1] > a[j])
			{
				swap(a[j + 1], a[j]);
			}
		}
	}
}

快速排序

快速排序是Hoare大佬于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

hoare版

left代表左边第一个元素,right代表右边第一个元素

1.找到一个基准值(key)

2.left向左移动,找到比key大的就停止

3.right向右移动,找到比key小的就停止

4.将left和right交换

5重复234操作,直到left对应的下标=right对应的下标就停止


代码如下

void PartSort1(int* a, int l, int r)
{
	if (l >= r)
	{
		return;
	}
	//取左边
	//int key_i = l;

	//随机取
	//int key_i = l + rand() % (r - l);

	//三数取中
	int key_i = GetNum(a, l,r);

	if (key_i != l)
	{
		swap(a[key_i], a[l]);
		key_i = l;
	}
	int begin = l;
	int end = r;

	while (l < r)
	{
		while (l < r && a[r] >= a[key_i])
		{
			r--;
		}

		while (l < r && a[l] <= a[key_i])
		{
			l++;
		}

		swap(a[l], a[r]);
	}

	swap(a[key_i], a[l]);
	key_i = l;

	PartSort1(a, begin, key_i - 1);
	PartSort1(a, key_i + 1, end);

}

可以用三数取中和随机选数来进行选择基准值上的优化

挖坑版

挖坑版也挺好理解的

1.先找一个基准值(key),形成一个坑位(hole,hole是下标)

2.很hoare一样,left从左边开始移动,遇到比key大的就停止,然后将这个比key的数字填到坑里面,然后将坑hole的位置移动到left的位置,形成新坑

3.right从右边开始移动找小,然后将小的数字填在坑里面,坑的位置更新到right的位置

4.重复2和3,直到left==right


代码如下

void PartSort2(int* a, int l, int r)
{
	if (l >= r)
	{
		return;
	}

	int key = a[l];
	int hole = l;
	
	int bg = l;
	int ed = r;

	while (l < r)
	{
		while (l < r && a[r] >= key)
		{
			r--;
		}
		a[hole] = a[r];
		hole = r;
		
		while (l < r && a[l] <= key)
		{
			l++;
		}

		a[hole] = a[l];
		hole = l;
		
	}

	a[hole] = key;


	PartSort2(a, bg, hole - 1);
	PartSort2(a, hole + 1, ed);
}

前后指针法

1.依旧是选出一个基准值(key)

2.定义一个prev指向序列的开头,一个cur指向prev的下一个位置

3.若cur指向的数据小于key,则将prev向后移动,移动之后若prev和cur的位置没有重合,则将cur对应的数据和prev对应的数据进行交换,然后cur++,(不管prev移动不移动,cur都要向后移动)

4.重复第三步,直到cur <= 序列的有边界。


代码如下

void PartSort3(int* a, int l, int r)
{
	if (l >= r)
	{
		return;
	}

	int bg = l;
	int ed = r;

	int cur = l + 1;
	int prev = l;

	int key_i = l;

	while (cur <= r)
	{
		if (a[cur] < a[key_i] && ++prev != cur)
		{
			swap(a[cur], a[prev]);
		}
		++cur;
	}

	swap(a[prev], a[key_i]);


	PartSort3(a, bg, prev - 1);
	PartSort3(a, prev + 1, ed);
}

归并排序

归并排序

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

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

相关文章

Python中的@cache有什么妙用?

Python中的cache有什么妙用&#xff1f; 本文同步投给#创作纪念日#活动&#xff0c;2019年4月8日我在C站发了第一篇博文&#xff0c;至今200多篇了&#xff0c;感兴趣可以访问我的主页&#xff1a;小斌哥ge。 看到官方发的私信&#xff0c;是鼓励博主写一些感悟&#xff0c;由于…

【MySQL】数据库基础知识

1、数据库简介 1.1 什么是数据库 数据库其实就是"基于数据结构"实现出来的一类软件&#xff0c;这类软件可以用来对数据进行管理&#xff0c;管理也就是对数据进行增删查改等一些操作 为什么说数据库是基于数据结构实现出来的"一类软件"呢&#xff1f; 答&…

本地化部署大语言模型 ChatGLM

本地化部署大语言模型 ChatGLM 本地化部署大语言模型 ChatGLM前期筹备GitHub 基础包语言模型文件基础配置显存查看方法 Anaconda 模块Anaconda 环境创建根目录操作基础依赖加载transformers 和 protobuf 库加载Pytorch 源修改依赖库补充补充依赖 pypi 配置cchardet 依赖错误解决…

开放式耳机好用吗,盘点几款口碑不错的开放式耳机

​开放式耳机作为一种全新的耳机形态&#xff0c;已经成为了当前市场上非常火爆的一款产品。由于无需入耳佩戴&#xff0c;可以很好的避免了耳膜受到损伤&#xff0c;而且也能够让我们在佩戴眼镜时也能够正常使用。加上开放式耳机的音质和舒适度都要优于其他类型的耳机&#xf…

全球上线!ABB中国涡轮增压器分拆 – 数据清理阶段完成

ABB是数字行业的技术前沿者&#xff0c;拥有四项主营业务&#xff1a;电气化&#xff0c;工业自动化&#xff0c;运动控制以及机器人和离散自动化。ABB总部位于瑞士苏黎世&#xff0c;业务遍及100多个国家&#xff0c;拥有约105&#xff0c;000名员工。2021年&#xff0c;该公司…

dockerDesktop依赖wsl,及docker可视化推荐Portainer

也是今天无意中发现的Portainer 之前采用的1panel和宝塔做运维可视化 现在换成dockerPortainer 宝塔和1panel和portranier对比 宝塔广告太多&#xff0c;而且不适合深入了解运维技术 1panel个人感觉无广告颜值很高&#xff0c;但是还是有局限&#xff0c;不适合深入了解运维…

MAC 用 brew安装 mysql并且设置开机自启动

目录 一.安装 mysql 1.安装 mysql 2.启动 mysql 3.关闭 mysql 4.初次安装需要修改 root 密码 5.验证密码 二.设置开机启动 1.找到plist 文件 2.将启动文件 plist 复制到 LaunchAgents目录 3.验证 一.安装 mysql 1.安装 mysql 1.安装默认版可以直接执行安装命令 brew…

上岸美团,我的面经!

作者&#xff1a;阿秀 校招八股文学习网站&#xff1a;https://interviewguide.cn 这是阿秀的第「257」篇原创 小伙伴们大家好&#xff0c;我是阿秀。 欢迎今年参加秋招的小伙伴加入阿秀的学习圈&#xff0c;目前已经超过 2200 小伙伴加入&#xff01;去年认真准备和走下来的基…

GreenPlum (一) 初识

在开始了解GreenPlum之前&#xff0c;应该对这种产品的诞生有基本的了解&#xff0c;搭建一个基本的知识框架。对以下历史有基本了解之后应对下文术语进行基本阅读。 ​ 阅读目标: 阅读完成后需要对相关术语以及greenplum有基础理解。 文案基本互联网相关blog进行整体汇总&…

苹果跌倒检测新专利获得,结合苹果Find My可准确定位

苹果首款“跌倒检测”功能专利可追溯到 2018 年公示的 20190103007&#xff0c;后续又获得了至少 5 项相关专利。根据美国商标和专利局&#xff08;USPTO&#xff09;上周四公示的专利&#xff0c;苹果公司再次获得了一项“跌倒检测”功能专利。 苹果在报告中表示&#xff0c…

亚马逊云科技让你在云端发现企业穿越周期稳健发展的力量

2023年3月29日「哈佛商业评论-未来管理沙龙」活动盛大启幕&#xff0c;此次沙龙活动以穿越周期的力量为主题方向&#xff0c;以解码跨国企业持续增长源动力为主旨&#xff0c;希望为企业高层管理者们带来更多思考和启迪。 作为特邀嘉宾&#xff0c;亚马逊全球副总裁、亚马逊云…

内存的分区

目录 内存分区介绍 区域功能 内存分区运行前后的区别 运行之前&#xff08;代码区数据区未初始化数据区&#xff09; 运行之后&#xff08;代码区数据区未初始化数据区栈区堆区&#xff09; 缓冲区 缓冲区有什么用&#xff1f; 缓冲区的三种类型 缓冲区的刷新 内存分布图 栈与堆…

AI绘画——ControlNet扩展安装教程

目录 1.ControlNet安装 2.预处理模型安装 预处理模型&#xff08;annotator&#xff09;下载链接&#xff1a; 预处理模型安装地址&#xff1a; 3.ControlNet模型下载 Controlnet模型下载地址&#xff1a; Controlnet模型安装目录&#xff1a; 注&#xff1a;&…

KDZRS-40A三通道变压器直流电阻测试仪

一、产品概述 变压器绕组的直流电阻测试是变压器在交接、大修和改变分接开关后的试验项目。在通常情况下&#xff0c;用传统的方法&#xff08;电桥法和压降法&#xff09;测量变压器绕组以及大功率电感设备&#xff08;发电机&#xff09;的直流电阻是一项费时费工的工作。为了…

VMware从零配置安装CentOS 7

不跳步图文详细安装教程 一、VMware的下载二、VMware的安装三、CentOS7的下载第一步&#xff1a;根据自己电脑操作系统的位数点击选择&#xff08;大多数都是64位操作系统&#xff09;第二步&#xff1a;任意挑选一个镜像源进入下载界面第三步&#xff1a;下载对应版本的CentOS…

比较运算符、关键字子查询MySQL数据库 (头歌实践教学平台)

文章目的初衷是希望学习笔记分享给更多的伙伴&#xff0c;并无盈利目的&#xff0c;尊重版权&#xff0c;如有侵犯&#xff0c;请官方工作人员联系博主谢谢。 目录 第1关&#xff1a;带比较运算符的子查询 任务描述 相关知识 子查询 带比较运算符的子查询 编程要求 第2关…

Spring Messaging-远程命令执行漏洞(CVE-2018-1270)

Spring Messaging-远程命令执行漏洞&#xff08;CVE-2018-1270&#xff09; 0x00 前言 spring messaging为spring框架提供消息支持&#xff0c;其上层协议是STOMP&#xff0c;底层通信基于SockJS&#xff0c;在spring messaging中&#xff0c;其允许客户端订阅消息&#xff0…

微服务 - Redis缓存 · 数据结构 · 持久化 · 分布式 · 高并发

一、分布式解决 Session 的问题 在单站点中&#xff0c;可以将在线用户信息存储在Session中&#xff0c;随时变更获取信息&#xff1b;在多站点分布式集群如何做到Session共享呢&#xff1f;架设一个Session服务&#xff0c;供多服务使用。 频繁使用的数据存在DB端&#xff0…

向隐形冠军学习:聚焦人效,用时间管理提效益

注&#xff1a; 本文来源于盖雅工场联合创始人兼CEO 章新波 在2023狮山论坛“ 向隐形冠军学习&#xff1a; 聚焦人效&#xff0c;用时间管理提效益 ”的主题分享。 文&#xff5c;章新波 整理 &#xff5c;盖雅学苑 在人力资源行业以及各大企业&#xff0c;「人效」这个词…

How to use CCS to debug a running M4F core that was started by Linux?

参考FAQ:AM62x & AM64x: How to use CCS to debug a running M4F core that was started by Linux? 问题记录&#xff1a; 1.使用SD卡启动模式&#xff0c;板上运行Linux。 当Linux系统启动后&#xff0c;9表示M4F core&#xff1a; am64xx-evm login: root rootam64xx…