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

十大排序之交换排序

文章目录

  • 十大排序之交换排序
    • 一、交换排序
      • [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)

👌稳定性:不稳定

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

相关推荐
客卿1237 分钟前
力扣--组合,子集--回溯法的再探索--总结回溯法
java·算法·leetcode
zh路西法8 分钟前
【C语言简明教程提纲】(四):结构体与文件定义和操作
android·c语言·redis
_日拱一卒9 分钟前
LeetCode(力扣):环形链表
算法·leetcode·链表
做怪小疯子12 分钟前
Leetcode刷题——链表就地反转
算法·leetcode·链表
仟濹24 分钟前
【算法打卡day22(2026-03-14 周六)今日算法or技巧:双指针 & 链表】9个题
数据结构·算法·链表·双指针
RechoYit32 分钟前
数学建模——评价与决策类模型
python·算法·数学建模·数据分析
leaves falling34 分钟前
Qt 项目:计算圆面积
开发语言·qt
xiaoye370834 分钟前
某大厂java面试题二面20260313
java·开发语言·spring
Full Stack Developme40 分钟前
Java -jar 命令 可以有哪些参数设置
java·开发语言·jar
地平线开发者1 小时前
地平线 Sparse 多任务参考算法 SparseBevFusionMultitaskOE-V1.0
算法·自动驾驶