数据结构9——排序

news2025/1/16 20:07:35

一、冒泡排序

冒泡排序(Bubble Sort),顾名思义,就是指越小的元素会经由交换慢慢“浮”到数列的顶端。

算法原理

  1. 从左到右,依次比较相邻的元素大小,更大的元素交换到右边;
  2. 从第一组相邻元素比较到最后一组相邻元素,这一步结束最后一个元素必然是参与比较的元素中最大的元素;
  3. 按照大的居右原则,重新从左到后比较,前一轮中得到的最后一个元素不参4与比较,得出新一轮的最大元素;
  4. 按照上述规则,每一轮结束会减少一个元素参与比较,直到没有任何一组元素需要比较。

代码实现

// 冒泡排序
void BubbleSort(int* arr, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; ++i) // 冒泡排序趟数
	{
		int j = 0;
		int flag = 1;
		for (j = 0; j < n - i - 1; ++j) // 待排序区间进行比较交换
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag == 1)
		{
			// 说明已经有序
			break;
		}
	}
}

 拓展:

 O(n^{2})

二、快速排序

快速排序(Quick Sort),是冒泡排序的改进版,之所以“快速”,是因为使用了分治法。它也属于交换排序,通过元素之间的位置交换来达到排序的目的。

算法原理

在序列中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区与大数区进行排序。

一趟快速排序的具体做法是:

  1. 设两个指针 i 和 j,分别指向序列的头部和尾部;
  2. 先从 j 所指的位置向前搜索,找到第一个比基准小的值,把它与基准交换位置;
  3. 再从 i 所指的位置向后搜索,找到第一个比基准大的值,把它与基准交换位置;
  4. 重复 2、3 两步,直到 i = j。

仔细研究一下上述算法我们会发现,在排序过程中,对基准的移动其实是多余的,因为只有一趟排序结束时,也就是 i = j 的位置才是基准的最终位置。

由此可以优化一下算法

  1. 设两个指针 i 和 j,分别指向序列的头部和尾部;
  2. 先从 j 所指的位置向前搜索,找到第一个比基准小的数值后停下来,再从 i 所指的位置向后搜索,找到第一个比基准大的数值后停下来,把 i 和 j 指向的两个值交换位置;
  3. 重复步骤 2,直到 i = j,最后将相遇点指向的值与基准交换位置。

代码:

void QuickSort(int array[], int low, int high) {
    int i = low; 
    int j = high;
    if(i >= j) {
        return;
    }
 
    int temp = array[low];
    while(i != j) {
        while(array[j] >= temp && i < j) {
            j--;
        }
	while(array[i] <= temp && i < j) {
            i++;
        }
	if(i < j) {
            swap(array[i], array[j]);
        }
    }
 
    //将基准temp放于自己的位置,(第i个位置)
    swap(array[low], array[i]);
    QuickSort(array, low, i - 1);
    QuickSort(array, i + 1, high);
}

三、插入排序

直接插入排序(Straight Insertion Sort),是一种简单直观的排序算法,它的基本操作是不断地将尚未排好序的数插入到已经排好序的部分,好比打扑克牌时一张张抓牌的动作。在冒泡排序中,经过每一轮的排序处理后,序列后端的数是排好序的;而对于插入排序来说,经过每一轮的排序处理后,序列前端的数都是排好序的。

算法原理

先将第一个元素视为一个有序子序列,然后从第二个元素起逐个进行插入,直至整个序列变成元素非递减有序序列为止。如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入大相等元素的后面。整个排序过程进行 n-1 趟插入

代码:

//========================写法1=======================
void insert_sort(int *arr, int len){
	int i, j;
	for (i = 1; i < len; i++){
		int tmp = arr[i];//待插入数
		for (j = i; j > 0 && arr[j - 1] > tmp; j--){
			arr[j] = arr[j - 1];//大的数依次右移
		}
		arr[j] = tmp;
	}
}

//==========================写法2======================
void insert_sort_1(int *arr, int n)
{
	int i = 0, j = 0;

	for (i = 1; i < n; i++)
	{
		j = i;
		//一直拿当前数与前面数比,有<=它的就停止,没有接着交换位置并往前比
		while (j >= 1)
		{
			if (arr[j] < arr[j - 1])	
			{
				swap(arr, j, j - 1);
			}
			j--;
		}
	}
}

四、希尔排序

希尔排序(Shell’s Sort)是第一个突破 O(n²) 的排序算法,是直接插入排序的改进版,又称“缩小增量排序”(Diminishing Increment Sort)。它与直接插入排序不同之处在于,它会优先比较距离较远的元素。

算法原理

先将整个待排序列分割成若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

子序列的构成不是简单地“逐段分割”,将相隔某个增量的记录组成一个子序列,让增量逐趟缩短,直到增量为 1 为止

 

代码实现

这里的代码是通过一次就把所有元素排序完成。

  • gap的取值保证最后为1就可以了
  • gap不等于1之前其实都是预排序,让数据趋近于有序。
// 希尔排序
void ShellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;//保证最后gap为1就可以了
		int i = 0;
		for (i = 0; i < n - gap; ++i)//多组元素同时进行插入排序
		{
			int end = i;
			int tmp = arr[end+gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end+gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

五、选择排序

每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的元素排序完。

原理
每次从无序区间中选取一个最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的元素排序完。

在元素集合中a r r [ i ]   a r r [ n − 1 ] arr[i]~arr[n-1]arr[i] arr[n−1]中选择最大(最小的元素)
若它不是这组元素中的最后一个(第一个元素),则将它与这组元素中的最后一个(第一个)元素交换
在剩余的a r r [ i ]   a r r [ n − 2 ] arr[i]~arr[n-2]arr[i] arr[n−2]集合中,重复此步骤,直到集合中剩余一个元素为止

 

代码:

// 选择排序
void SelectSort(int* arr, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; ++i)
	{
		int minIndex = i;//记录待排序区间最小元素下标
		int j = 0;
		for (j = i + 1; j < n; ++j)
		{
			if (arr[minIndex] > arr[j])
			{
				minIndex = j;
			}
		}
		int tmp = arr[minIndex];
		arr[minIndex] = arr[i];
		arr[i] = tmp;
	}
}

六、堆排序

堆排序是利用数据结构堆的特性来进行排序,它也是一种选择排序,它通过堆来选取数据。排升序建大堆,排降序建小堆。
堆的详细介绍可以看这一篇文章数据结构堆的详解

原理
每次将堆顶元素和最后一个元素进行交换,再进行向下调整,然后缩小待排序区间,直到数据有序,因为堆顶的元素一定是一组数据中的最大或者最小值。

注意:向下调整的前提是,这个根节点的左右子树一定要是一个堆(大堆或小堆)

代码

void HeapAdjust(int* arr, int start, int end)
{
	int tmp = arr[start];
	for (int i = 2 * start + 1; i <= end; i = i * 2 + 1)
	{
		if (i < end&& arr[i] < arr[i + 1])//有右孩子并且左孩子小于右孩子
		{
			i++;
		}//i一定是左右孩子的最大值
		if (arr[i] > tmp)
		{
			arr[start] = arr[i];
			start = i;
		}
		else
		{
			break;
		}
	}
	arr[start] = tmp;
}
void HeapSort(int* arr, int len)
{
	//第一次建立大根堆,从后往前依次调整
	for(int i=(len-1-1)/2;i>=0;i--)
	{
		HeapAdjust(arr, i, len - 1);
	}
	//每次将根和待排序的最后一次交换,然后在调整
	int tmp;
	for (int i = 0; i < len - 1; i++)
	{
		tmp = arr[0];
		arr[0] = arr[len - 1-i];
		arr[len - 1 - i] = tmp;
		HeapAdjust(arr, 0, len - 1-i- 1);
	}
}
int main()
{
	int arr[] = { 9,5,6,3,5,3,1,0,96,66 };
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	printf("排序后为:");
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

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

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

相关文章

【Java】Java基础语法

一、注释详解 1.1 注释的语法&#xff1a; // 单行注释/*多行注释 *//**文档注释 */ 1.2 注释的特点&#xff1a; 注释不影响程序的执行&#xff0c;在Javac命令进行编译后会将注释去掉 1.3 注释的快捷键 二、字面量详解 2.1 字面量的概念&#xff1a; 计算机是用来处理…

Bandzip:打破压缩界限,文件管理更高效

名人说&#xff1a;&#xff1a;一点浩然气&#xff0c;千里快哉风。 ——苏轼 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、软件介绍1、Bandzip2、核心特点 二、下载安装1、下载2、安装 三、使用方法 很高兴…

拖拽劫持与数据窃取

2010 年&#xff0c;ClickJacking 技术有了新的发展。一位名叫 Paul Stone 的安全研究者在 BlackHat 2010 大会上发表了题为“Next Generation Clickjacking”的演讲。在该演讲中&#xff0c;提出了“浏览器 拖拽事件”导致的一些安全问题。 目前很多浏览器都开始支持 Drag &a…

【pytorch05】索引与切片

索引 a[0,0]第0张图片的第0个通道 a[0,0,2,4]第0张图片&#xff0c;第0个通道&#xff0c;第2行&#xff0c;第4列的像素点&#xff0c;dimension为0的标量 选择前/后N张图片 a[:2,:1,:,:].shape前两张图片&#xff0c;第1个通道上的所有图片的数据 a[:2,1:,:,:].shape前两张…

智能优化算法改进策略之局部搜索算子(八)--Powell方法

1、原理介绍 Powell方法[1]是一种无约束优化算法&#xff0c;又称为方向加速法&#xff0c;用于寻找多变量函数的极小值。其基本思想是在迭代中逐次产生Q共轭方向组&#xff0c;本质上它属于不需计算导数的共轭方向法。每次迭代后&#xff0c;算法会更新搜索方向&#xff0c;并…

【Android源码解析】一篇搞定“路由、网络层、UI层、通信层

资料获取 扫一扫下方二维码即可免费领取1880页的《Android百大框架源码解析》 《Android 百大框架源码解析》 1.Retrofit 2.0源码解析 2.Okhttp3源码解析 3.ButterKnife源码解析 4.MPAndroidChart 源码解析 5.Glide源码解析 6.Leakcanary 源码解析 7.Universal-lmage-Loa…

如何解决vue中的路由守卫失效问题

引言 1. 路由守卫简介 路由守卫是前端开发中一个至关重要的概念&#xff0c;特别是在使用单页应用&#xff08;SPA&#xff09;框架如React、Vue或Angular时。它们充当了SPA中的“门卫”&#xff0c;控制着用户对不同页面的访问权限。路由守卫的核心功能是确保用户在访问特定…

ChatGPT-4o也参加高考了,还写了六大考卷的全部作文! |【WeThinkIn出品】

写在前面 【WeThinkIn出品】栏目专注于分享Rocky的最新思考与经验总结&#xff0c;包含但不限于技术领域。欢迎大家一起交流学习&#x1f4aa; 欢迎大家关注Rocky的公众号&#xff1a;WeThinkIn 欢迎大家关注Rocky的知乎&#xff1a;Rocky Ding AIGC算法工程师面试面经秘籍分享…

51-52Windows密码安全性测试与Windows提权

目录 Windows密码安全性测试 一、本地管理员密码如何直接提取 1、直接通过mimikatz读取管理员密码 2、使用laZagne工具读取管理员密码 二、利用Hash远程登录系统 window提权 三、远程webshell执行命令解决 不能执行原因&#xff1a; 解决方法&#xff1a;单独上传cmd.e…

Java——封装(Encapsulation)

一、封装简介 1、封装是什么 封装&#xff08;Encapsulation&#xff09;是面向对象编程&#xff08;OOP&#xff09;中的一个基本概念&#xff0c;它指的是将对象的状态&#xff08;数据&#xff09;和行为&#xff08;方法&#xff09;绑定在一起&#xff0c;并对外隐藏对象…

YouTube API接口:一键获取Playlist视频合集信息

核心功能介绍 在视频内容日益繁荣的今天&#xff0c;YouTube作为全球领先的视频分享平台&#xff0c;为内容创作者、品牌商家以及数据分析师提供了丰富的视频资源。其中&#xff0c;Playlist视频合集作为YouTube上的一种特色内容形式&#xff0c;深受用户喜爱。为了更好地满足…

个性化光标和动态壁纸

光标 进入这个宝藏网页至美化 至美化 进入鼠标页面&#xff0c;选择自己喜欢的鼠标&#xff0c;进入相关页面 分为两种&#xff0c;那么热爱有钱的UU可以选择高清版 像我这种没钱的孩子或者觉得试用版够用的就使用上面的 点击下载 进入自己的文件夹&#xff0c;解压成功之…

idea添加文档注释

一、easy javadoc插件 在settings的plugins中下载easy javadoc插件。 安装完成后重启idea&#xff0c;再次打开settings界面。会出现easyDoc相关配置。 二、设置模版以及使用 类描述模版参考设置&#xff1a; /** * 类描述 -> * * Author: ywz * Date: $Date$ */ 方法描述…

人脸识别技术:前沿应用与业务场景探索

随着科技的飞速发展&#xff0c;人脸识别技术已经成为我们日常生活中不可或缺的一部分。这项技术以其独特的生物特征识别能力&#xff0c;在公共安全、金融、交通、教育等多个领域展现出巨大的潜力和价值。本文将深入探讨人脸识别技术的原理、业务场景以及相关的成功案例。 一、…

示例:推荐一个自定义的Ribbon皮肤

一、目的&#xff1a;WPF自带的Ribbon控件功能很强大&#xff0c;但使用过程中感觉显示的样式不是很好&#xff0c;或者不适合自己的项目&#xff0c;下面介绍一个基于自带Ribbon控件样式的修改&#xff0c;主要修改了些高度&#xff0c;间距&#xff0c;背景色&#xff0c;前景…

借助ChatGPT降低学术论文重复率,使用技巧全攻略,实用有效,快速上手

大家好&#xff0c;感谢关注。我是七哥&#xff0c;一个在高校里不务正业&#xff0c;折腾学术科研AI实操的学术人。可以&#xff08;yida985&#xff09;交流学术写作或ChatGPT等AI领域相关问题&#xff0c;多多交流&#xff0c;相互成就&#xff0c;共同进步。 经常有学术同…

文心智能体平台介绍和应用:制作你的智能体(运维小帮手)

这是我自己制作的智能体 大家可以了解一下&#xff01; 运维小帮手&#xff01;https://mbd.baidu.com/ma/s/tE19dqvr 文心智能体平台官网首页 点击跳转&#xff01;https://agents.baidu.com/ 什么是智能体平台&#xff1f; 文心智能体平台&#xff08;Wenxin Intelligen…

【Leetcode】520. 检测大写字母

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517;我们定义&#xff0c;在以下情况时&#xff0c;单词的大写用法是正确的&#xff1a; 全部字母都是大写&#xff0c;比如 “USA” 。单词中所有字母都不是大写&#xff0c;比如 “le…

腾讯云[HiFlow】| 自动化 -------HiFlow:还在复制粘贴?

文章目录 前言&#xff1a;一&#xff1a;HiFlow是什么二&#xff1a;功能介绍1.全连接2.自动化2.1定时处理特定任务2.2实时同步变更信息2.3及时获取通知提醒 3.零代码4.多场景5.可信赖 三&#xff1a;用户体验最后 前言&#xff1a; 随着网络时代的不断发展&#xff0c;自动化…

java内置线程池

线程池常见方法 如何获取线程池对象 缓存线程池 自定义任务对象 public class MyRunnable implements Runnable{private int id;public MyRunnable(int id) {this.id id;}Overridepublic void run() {String name Thread.currentThread().getName();System.out.println(&quo…