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

十大排序之交换排序

文章目录

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

👌稳定性:不稳定

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

相关推荐
爱装代码的小瓶子2 小时前
【C++与Linux基础】文件篇(8)磁盘文件系统:从块、分区到inode与ext2
linux·开发语言·c++
MM_MS2 小时前
Halcon图像点运算、获取直方图、直方图均衡化
图像处理·人工智能·算法·目标检测·计算机视觉·c#·视觉检测
cyforkk2 小时前
13、Java 基础硬核复习:泛型(类型安全)的核心逻辑与面试考点
java·开发语言·面试
每天要多喝水2 小时前
贪心算法专题Day22
算法·贪心算法
ujainu2 小时前
Flutter + OpenHarmony 游戏开发进阶:动态关卡生成——随机圆环布局算法
算法·flutter·游戏·openharmony
PPPPPaPeR.2 小时前
程序地址空间
linux·算法
苦藤新鸡2 小时前
51.课程表(拓扑排序)-leetcode207
数据结构·算法·leetcode·bfs
senijusene2 小时前
数据结构与算法:栈的基本概念,顺序栈与链式栈的详细实现
c语言·开发语言·算法·链表
2603_949462102 小时前
Flutter for OpenHarmony 社团管理App实战 - 资产管理实现
开发语言·javascript·flutter