十大排序算法——交换排序(一)

十大排序之交换排序

文章目录

  • 十大排序之交换排序
    • 一、交换排序
      • [1.1 冒泡排序](#1.1 冒泡排序)
      • [1.1.1 冒泡排序时间复杂度](#1.1.1 冒泡排序时间复杂度)
      • 1.2快速排序(快排)
        • [1.2.1 Hoare 版本排序法](#1.2.1 Hoare 版本排序法)
        • [1.2.2 前后指针法](#1.2.2 前后指针法)
        • [1.2.3 挖坑法](#1.2.3 挖坑法)
        • [1.2.4 快排的时间复杂度](#1.2.4 快排的时间复杂度)

一、交换排序

1.1 冒泡排序

冒泡排序是一种最基础的排序方式,因为每一个元素都可以像小气泡一样,根据自身的大小像数组的一侧进行移动

代码实现:

c 复制代码
void Swap(int* x, int* y)
{
	int tmp;
	tmp = *x; *x = *y; *y = tmp;
}
void Bubblesort(int* a, int n)
{
	int flag = 0;
	for (int j = 0; j < n; j++)
	{
		for (int i = 1; i < n-j; i++)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				flag = 1;
			}
		}
		if (flag == 0)
			break;
	}
}

1.1.1 冒泡排序时间复杂度

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

在实际情况中由于冒泡排序效率低下,常常只具有教学意义,没有实际应用意义。

1.2快速排序(快排)

快速排序是Hoare于1962年提出的⼀种**⼆叉树结构** 的交换排序⽅法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两⼦序列,左⼦序列中所有元素均⼩于基准值,右⼦序列中所有元素均⼤于基准值 ,然后最左右⼦序列重复该过程 ,直到所有元素都排列在相应位置上为⽌。
快排基本框架

c 复制代码
void QuickSort(int* a,int left,int right)
{
	if(left>=right)
		return;
	int meet= _QuickSort(a,left,right);
	QuickSort(a,left,meet-1);
	QuickSort(a,meet+1,right);
}
1.2.1 Hoare 版本排序法


算法思路

  1. 创建左右指针,确定基准值
  2. 从右向左找出比基准值小的数据,从左向右找出比基准值大的数值,左右数值交换,进入下一个循环
    问题一:怎么就一定确定left和right相遇后所在的数值比key值小?
c 复制代码
 int _HoareQuickSort(int* a,int left,int right)
 {
 	int begin=left;
 	int keyi=left;
 	int end=right;
 	while(left<right)
 	{
 		while(left<rigth&&a[left]<a[keyi])
 			left++;
 		while(left<rigth&&a[right]>a[keyi])
 			right--;
 		Swap(&a[left],&a[right]);
 	}
 	Swap(&a[keyi],&a[right]);
 	return right;
 }
 

问题一解答:

问题2:key值怎么选才能最好的?

key值选不好可能会出现如下情况:

如果数组元素个数过大,会导致右边递归层次过深,可能会有栈溢出的风险

为避免出现这种情况,我们采取三数取中法进行选key值

c 复制代码
int Getmid(int* a,int left,int right)
{
	int mid=(left+right)/2;
	if(a[left]>a[right])
	{
		if(a[mid]>a[left])
		{
			return left;
		}
		else if(a[mid]<a[right])
			return right;
		else
				return mid;
	}
	if(a[left]<a[right])
	{
		if(a[mid]>a[right])
		{
			return right;
		}
		else if(a[mid]<a[left])
			return left;
		else
				return mid;
	}
}

将三数取中法融入到_HoareQuickSort排序中

c 复制代码
int _HoareQuickSort(int* a,int left,int right)
 {
 	int begin=left;
 	//三数取中法取keyi
 	int midi=Getmid(a,left,right);
 	Swap(&a[midi],&a[left]);
 	int keyi=left;
 	//
 	int end=right;
 	while(begin<end)
 	{
 			//右边先走,右边找小
 		  while(begin<end&&a[end]>a[keyi])
 				--end;
 			//左边找大
 			while(begin<end&&a[left]<a[keyi])
 				++begin;
 		Swap(&a[begin],&a[end]);
 	}
 	Swap(&a[keyi],&a[begin]);
 	return begin;
 }
1.2.2 前后指针法

动图图解

  • 优点:不用在进行判断左边先走还是右边先走
  • 思路:1.先选择一个key值,prev指针开始指向序列开头,cur指针指向prev的下一个,2.cur先走,当cur指针指向的数小于key值,停下来,prev后移一位,交换两个数,当cur指向的值小于key,cur++,prev++;3. 重复以上步骤,直到cur越界,prev当前指向的位置与key互换,依次递归
    代码如下:
c 复制代码
int _PointerQuickSort(int* a,int left,int right)
{
	//三数取中选key值
	int midi=Getmid(a,left,right);
 	Swap(&a[midi],&a[left]);
 	int keyi=left;
 	int prev=left;
 	int cur=prev+1;
 	while(cur<=right)
 	{
 		if(a[cur]<a[keyi]&&++prev!=cur)//避免prev和cur指向一个位置,自己和自己交换
 		{
 			Swap(&a[prev],&a[cur]);
 		}
 		cur++;
 	}
 	Swap(&a[keyi],&a[prev]);
 	return prev;
}
1.2.3 挖坑法

图解:

  • 思路:开始的时候key值先储存起来,key值所在位置是坑,右边先走找小,互换坑位,再左边走找大互换坑位,左右相遇,将key值放在相遇的位置。
  • 优点:左边是坑,一定是右边先走;右边是坑,一定是左边先走;不用纠结谁先走的问题
    代码示例:
c 复制代码
int HoleQuickSort(int* a,int left,int right)
{
	//三数取中选key值
	int midi=Getmid(a,left,right);
 	Swap(&a[midi],&a[left]);
 	int keyi=left;
 	
 	int key=a[keyi];
 	int hole=left;
 	int begin=left,end=right;
 	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;
}
1.2.4 快排的时间复杂度

👌快速排序的递归方法和二叉树的向上调整类似,时间复杂度是O(N* l o g 2 N log_2N log2N)

三种递归方法的时间复杂度是一样的,只不过理解方式不同。

👌空间复杂度:O( l o g 2 N log_2N log2N)

👌稳定性:不稳定

😎下一节预告:插入排序(直接插入,希尔排序)

相关推荐
AgentMaster26 分钟前
数据资产化落地难题:5款数据中台系统架构对比与实施记录
大数据·人工智能·算法
泡海椒41 分钟前
jquick-pdf 防止 PDF 内容分页断裂:keepTogether 属性妙用
java·开发语言·pdf
Logic10142 分钟前
C语言/数据结构动态规划题解:Kadane算法求最大子数组和——O(n)时间O(1)空间
c语言·数据结构·动态规划·贪心·时间复杂度·算法题·最大子数组和
鹿角片ljp1 小时前
从 Kimi Cyber Reasoning 学习网络安全推理数据集:从 Reasoning SFT 到安全 Agent 数据设计
数据结构·算法
雷✘2 小时前
C 程序从源文件到运行:预处理、编译、汇编、链接重定位与执行环境
c语言
传奇开心果编程2 小时前
【Rust入门练中学】 第1课:从零开始
开发语言·学习·rust
residual_fan2 小时前
航空发动机故障诊断专用智能体(三):基于对比学习的时序特征区分方法
人工智能·算法·数据挖掘·数据分析
Logic1012 小时前
C语言/数据结构位运算题解:异或XOR找出数据表中的“独特编号“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
高亦真2 小时前
今天是学习嵌入式的第39天
linux·学习·算法