排序方法大汇总

以下所有排序方法均以排升序为例

一.插入排序

1.直接插入排序

1>方法介绍:假定前n个数据有序,将第n+1个数据依次与前n个数据相比,若比第i个数据小且比第i-1个数据大则插入两者之间

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

   空间复杂度:O(1)

   稳定性:稳定

3>代码实现:

//插入排序
void InsertSort(int* a, int n)
{
	//在前n个数据有效情况下,将第n+1个数据往前面插入,并保持有序
	for (int j = 1; j < n; j++)
	{
		for (int i = j; i > 0; i--)
		{
			if (a[i] < a[i - 1])
			{
				Swap(&a[i], &a[i - 1]);
			}
		}
	}
}

补:当数据量非常大时,直接插入排序的效率会大大降低,这时我们可以采用每次相差gap个数据进行插入排序,依次减小gap,直至gap==1,可以提高效率,这就是所谓的希尔排序

2.希尔排序

1>方法介绍:

1)预排序+直接插入排序

先选定一个gap,从第一个数据开始,按gap进行跳隔分组,对区间端点处的数据进行插入排序,依次向后进行gap间隔分组,直至遇到和第一次分组重合的元素;再减小gap的数值,重复上述操作,直至gap==1(最后依次相当于直接插入排序,不过此时数组已经接近有序,效率会大大提高)

2)对于gap的确定:大量实现表明,gap=gap/3+1最为合适,+1是为了保证最后一次gap==1

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

   注:不同的书中对于希尔排序的时间复杂度描述不一样,读者记住该数值即可

   空间复杂度:O(1)

   稳定性:不稳定

3>代码实现:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		//改变每次跳的间隔,不断精细化
		gap = gap / 3 + 1;
		//所有分组
		for (int j = 0; j < gap; j++)
		{
			//仅针对一种划分方法
			for (int i = j; i < n - gap; i += gap)
			{
				if (a[i] > a[i + gap])
				{
					Swap(&a[i], &a[i + gap]);
				}
			}
		}
	}
}

二.选择排序

1.选择排序

1>方法介绍:在每一次遍历数组时找出最大值和最小值,分别放在首尾,逐渐向中间逼近

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

   空间复杂度:O(1)

   稳定性:稳定

3>代码实现:

//选择排序
void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin <= end)
	{
		int mini = begin;
		int maxi = begin;
		//寻找最大值,最小值的下标
		for (int i = begin+1; i <= end; i++)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			if (a[maxi] < a[i])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		//防止出现begin处的值被使用两次的情况
		if (begin == maxi)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		begin++;
		end--;
	}
}

2.堆排序

1>方法介绍:

1)利用数组中的数据建大堆,交换最后一个数据与第一个数据进行调整,使前n-1个数据仍为大堆,重复操作

2)利用数组中的数据建大堆的方法:利用向下调整法(具体可参考小编二叉树的顺序结构的博客),从非叶子节点的最后一个父节点开始向下调整

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

   空间复杂度:O(1)

   稳定性:稳定

3>代码实现:

void AdjustDown(int* a,int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if ((child+1)<size && a[child] < a[child + 1])
		{
			child++;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

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.冒泡排序

1>方法介绍:两两比较,将大数沉底,依次进行,直至有序

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

   空间复杂度:O(1)

   稳定性:稳定

3>代码实现:

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

2.快排序

1>方法介绍:

1)选定左边的数据为key,定义Left,Right两个下标,先让R先走,如果找到比key小的数据则停下来,再让L走,如果找到比key大的数据则停下来,交换这两个数据,再重复操作,直至L与R相遇,交换相遇位置的数据(一定比key小)和key。此时key左边的数据全部比key小,右边的数据全部比key大,对key左边和右边的两个数组再进行上述操作(递归实现),若数组中只有一个数据或L大于R则停下来

2)优化1:若数组为逆序排列,则只进行右侧的递归展开,若层数太多会导致栈溢出,为了避免逆序的情况,我们可以对key的取值做文章:要么随机取key,但随机性太大,pass;要么取左中右三者中居中的数据,与左边数据交换,仍让左边数据为key

3)优化2:当数组中的数据量过少时,利用递归排序的代价太大,此时我们可以选用其他方法来排这些数据,以提高性能

2>关于相遇位置的数据小于key的解释:

若最后是L遇R:由于R先走,并且R找到比key小的数据才停下来,故R停下来的位置处的数据小于key,此时L走一直未找到比key大的数据直至与R相遇,所以相遇位置的数据小于key

若最后是R遇L:由于R先走,在最后一次R走前,L找到比key大的数据,R找到比key小的数据,两者进行交换,故L所在位置的数据是比key小的数据,之后R向前走,一直为找不到比key大的数据,直至与L相遇,所以相遇位置的数据小于key

综上所述:相遇位置的数据必定小于key

3>时间复杂度:O(N*logN)

   空间复杂度:O(logN)

   稳定性:不稳定

4>代码实现:

int GetMidi(int* a,int left, int right)
{
	int mid = (right + left) / 2;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[right] < a[left])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[right] > a[left])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}

//当数组为逆序时,递归层次太多,可能造成栈溢出,导致性能低下
//解决方法:1.将key取头,尾,中间三者中居中的值(三数取中)
//          2.进行随机选取key(该法不确定性太大,不推荐)
//当数据太少用递归进行排序会浪费空间,故可以在最后10个数据排序时改用其他方法排序,以提高性能
void QuickSort(int* a, int left,int right)
{
	if (left >= right)
	{
		return;
	}

	//小区间优化
	if ((right - left + 1 ) < 10)
	{
		InsertSort(a+left, right - left + 1);
	}
	else
	{
		int midi = GetMidi(a, left, right);
		Swap(&a[midi], &a[left]);

		int keyi = left;
		int begin = left;
		int end = right;
		while (begin < end)
		{
			//右边先走,找比key小的值
			while (begin < end && a[keyi] < a[end])
			{
				end--;
			}
			//左边后走,找比key大的值
			while (begin < end && a[keyi] > a[begin])
			{
				begin++;
			}
			//交换左右值
			Swap(&a[begin], &a[end]);
		}
		//将相遇位置的数据与key位置的数据交换
		Swap(&a[begin], &a[keyi]);

		QuickSort(a, left, keyi - 1);
		QuickSort(a, keyi + 1, right);
	}

}

四.归并排序

1.方法介绍:

1)按后序遍历的思想将数组分成若干份左右小区间

2)将数组细分成若干小组,让他们在自己的小组内有序,然后再让它与相邻的组别有序,依次向上归并

3)开辟一个新数组用于盛放已排序的数据,在一次归并后需将tmp中的数据拷贝回原数组中,以保证下一组更大区间的数据归并时是有序的

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

   空间复杂度:O(N)

   稳定性:稳定

3.代码实现:

void _MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin>=end)
		return;
	int midi = (begin + end) / 2;
	_MergeSort(a, tmp, begin, midi);
	_MergeSort(a, tmp, midi+1, end);

	//归并
	//[begin,mid],[mid+1,end]
	int begin1 = begin, end1 = midi;
	int begin2 = midi + 1, end2 = end;
	int i = 0;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(end - begin + 1));

}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, tmp, 0, n - 1);
	free(tmp);
	tmp = NULL;
}

注:对于快排和归并还有非递归的方法,考虑到篇幅,小编就不在这篇博客中介绍,如果有兴趣的小伙伴可以看看小编的下一篇博客了解以下哟

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法05-链表

介绍 基于结点的数据结构拥有独特的存取方式&#xff0c;因此在某些时候具有性能上的优势。 本章我们会探讨链表&#xff0c;它是最简单的一种基于结点的数据结构&#xff0c;而且也是后续内容的基础。 你会发现&#xff0c;虽然链表和数组看上去差不多&#xff0c;但在性能上…

ThingsBoard MQTT 连接认证过程 源码分析+图例

整个连接过程如图所示&#xff1a; 高清图片链接 1、环境准备 thingsboard3.5.1 源码启动。&#xff08;不懂怎么启动的&#xff0c;大家可以看我的博文ThingsBoard3.5.1源码启动&#xff09;MQTTX 客户端&#xff08;用来连接 thingsboard MQTT&#xff09;默认配置。queue.…

接口以及会话控制

接口 接口是前后端交互通信的桥梁 简单理解&#xff1a;一个接口就是服务中的一个路由规划&#xff0c;根据请求响应结果 接口的英文单词是API&#xff08;Application Program Interface),所以有时也称之为API接口 这里的接口指的是数据接口&#xff0c;与编程语言&#x…

python基础知识点总结(第二节判断与循环)

一、判断语句 1、if判断语句 ~if语句的基本格式 if 要判断的条件&#xff1a; 条件成立时&#xff0c;要做的事情 ~if语句的注意事项&#xff1a; 判断语句的结果一定要是布尔类型不要忘记判断条件后的&#xff1a;冒号归属于if语句的代码块&#xff0c;需要在前方填…

【软件测试】6.设计测试用例的设计方法

目录 1.基于需求的设计方法 2.具体的设计方法 2.1等价类 2.2边界值 2.3正交法 2.4判定表法 2.5场景法 2.6 错误猜测法 1.基于需求的设计方法 基于需求的设计方法也是总的设计测试用例的方法&#xff0c;在工作中&#xff0c;我们需要参考需求文档/产品规格说明书来设计…

告别鼠标,安卓模拟鼠标,绘图板,手写板操作电脑PC端,卡卡罗特也说好,儿童节快乐

家人们&#xff0c;上链接了&#xff1a;https://download.csdn.net/download/jasonhongcn/89387887 横屏模式&#xff1a; 竖屏模式&#xff1a; 操作说明&#xff1a; 1. 手势滑动模拟鼠标移动 2. 界面如果有滚动条&#xff0c;右手指按紧&#xff0c;通过左手指移动实现…

【智能算法】红嘴蓝喜鹊优化算法(RBMO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;S Fu受到自然界中红嘴蓝喜鹊社会行为启发&#xff0c;提出了红嘴蓝喜鹊优化算法&#xff08;Red-billed Blue Magpie Optimizer, RBMO&#xff09;。 2.算法原理 2.1算…

【原创】springboot+mysql员工管理系统

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

找出字符串中出现最多次数的字符以及出现的次数

str.charAt(i) 是JavaScript中获取字符串中特定位置字符的方法&#xff0c;表示获取当前的字符。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

Linux基础之进程控制--进程的创建和退出

目录 一、进程的创建 二、进程的终止 2.1 进程退出的场景 2.2 main()函数的返回值 2.3 用exit和_exit进行退出 2.4 进程异常终止 一、进程的创建 关于一个进程是如何被创建出来的&#xff0c;我们已经有所介绍这里我在给大家补充些东西。 首先&#xff0c;我们知道…

python之tkinter学习笔记

目录 Widget概览 加强版的tkinter模块 一、通用的 1.1、Label PhotoImage (gif图片加载) jpg图片加载 config方法-计时器 1.2、PanedWindow 1.3、LabelFrame 二、tkinter专有 2.1、Menu菜单复选框 2.2、工具栏 三、tkinter.ttk专有 3.1、Separator分隔线 3.2、n…

【C++】C++ 宾馆酒店管理系统(源码+数据+论文)【独一无二】(史上功能最全,拿来即用)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

LeetCode-47. 全排列 II【】

TOC 题目描述&#xff1a; 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2], [1,2,1], [2,1,1]] 示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输…

InnoDB Data Locking - Part 2.5 “Locks“ (Deeper dive)

All together now 现在让我们把在 InnoDB Data Locking – Part 2 “Locks” 中学习到的有关表锁和记录锁的知识结合起来&#xff0c;以理解以下情况&#xff1a; 我们看到&#xff1a; 第一个 SELECT * FROM t FOR SHARE; 在 5、10、42 和 supremum 伪记录上创建了 S 锁。…

【软件设计师】2022年上半年真题解析

​​冯诺依曼计算机体系结构的基本特点是&#xff1a; A. 程序指令和数据都采用二进制表示 - 这是正确的&#xff0c;因为冯诺依曼架构下的计算机使用二进制形式来表示和处理所有信息&#xff0c;包括指令和数据。 B. 程序指令总是存储在主存中&#xff0c;而数据则存储在高速…

Discuz_X3.5各行业资料文档下载模板

下载地址&#xff1a;Discuz_X3.5各行业资料文档下载模板

验证外星语词典

在解决算法题时&#xff0c;哈希表是经常被使用的工具&#xff0c;可以用来记录字符串中字母出现的次数&#xff0c;字符串中字符出现的位置等&#xff0c;这里用到的就是利用哈希表储存字符串中字符出现的的位置。 “外星语”的字母表顺序是不一样的&#xff0c;所以…

python数据预处理

PYTHON 最流行库&#xff1a;Numpy、Matplotlib 和 Pandas。Numpy 是满足所有数学运算所需要的库&#xff0c;由于代码是基于数学公式运行的&#xff0c;因此就会使用到它。Maplotlib&#xff08;具体而言&#xff0c;Matplotlib.pyplot&#xff09;则是满足绘图所需要的库。Pa…

创建一个支持切换阅读模式和答题模式的Anki问答题模板

为了备考某个需要默写的科目&#xff0c;做了个问答题笔记模板&#xff0c;如下&#xff1a; 在上图的回答栏填写答案后&#xff0c;点击显示答案按钮转到背面&#xff1a; 只实现上面的功能是很简单的&#xff0c;直接基于Anki自带的问答题模板添加自己需要的字段即可。问题…

嵌入式工程师人生提质的十大成长型思维分享

大家好,作为一名嵌入式开发者,很多时候,需要考虑个人未来的发展,人生旅途复杂多变,时常面临各种各样的挑战。如何在这个复杂多变的社会中稳步向前,不断成长,成为每个人都应该思考的问题。实际上,思维方式的差异决定我们应对挑战的能力与成长的速度。 第一:寻找自我坐…