首页 > 其他分享 >递归实现快速排序的三种方法

递归实现快速排序的三种方法

时间:2024-11-17 20:45:10浏览次数:3  
标签:arr right 递归 基准值 int 三种 排序 left

快速排序的定义


快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。

其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

个人一些见解

什么是递归?为什么递归可以实现快速排序?

很多人对于递归的认识只是局限于对函数的再次调用(比如说画函数递归图)

比如二叉树的先序遍历,但其实我们换一个角度想,为什么递归可以实现深度优先遍历的过程?

显然,递归可以实现快速排序也是满足于这种结构。

过程1:以某个元素为基准将数组划分为三部分,基准值左边小于它,右边大于它,这一步就完成了基准值位置的确定

过程2:将基准值左边的过程进行排序(会发现该过程也需要经历123)

过程2:将基准值右边的过程进行排序(会发现该过程同样需要经历123)

所以主函数的过程如下:

void QuickSort(int* arr, int left, int right)//快速排序主函数体
{
	if (left >= right)
		return;
    int div = PartSort(arr, left, right);//partsort函数是过程1的部分,下文会介绍三种方法
	QuickSort(arr, left, div - 1);//过程2
	QuickSort(arr, div + 1, right);//过程3
}

注:这里的left是要排序的左下标,right为右下标

需要注意的是:我们递归的结束条件

如果left>=right,则退出递归过程

接下来为你们讲诉一下快速排序完成过程1的三种方法

1.Hoare版本(左右指针)

我们可以设right下标对应的元素为key值,也就是基准值,实现代码如下

int Getmidindex(int* arr, int left, int right)//三个数找中间值
{
	int mid = (left + right) / 2;
	if (arr[left] > arr[mid])
	{
		if (arr[mid] > arr[right])
			return mid;
		else if (arr[left] < arr[right])
			return left;
		else
			return right;
	}
	else
	{
		if (arr[mid] < arr[right])
			return mid;
		else if (arr[left] > arr[right])
			return left;
		else
			return right;
	}
}
int PartSort1(int* arr, int left, int right)//快速排序之前后指针法,返回值为key的下标
{
	int mid = Getmidindex(arr, left, right);//该函数为三数其中,确保我们不会取最值
	swap(&arr[mid], &arr[right]);
	int keyindex = right;//右下标为基准值的下标
	while (left < right)
	{
		while (left < right && arr[left] <= arr[keyindex])//从左边找到大于基准值的元素
			left++;
		while (left < right && arr[right] >= arr[keyindex])//从右边找到小于基准值的元素
			right--;
		swap(&arr[left], &arr[right]);//将两个数交换
	}
	swap(&arr[left], &arr[keyindex]);//最后将基准值放在它的位置上
	return left;//返回基准值的下标,便于主函数体进行过程2  3
}

上述代码经常存在疑惑的点

为什么右边作为基准值要从左边出发?

其实这里是为了保证当left==right时,该位置对应的值是大于或者等于基准值的。

为什么基准值不能取最值?

2.挖坑法

int PartSort2(int* arr, int left, int right)//快速排序之挖坑法,返回值为key的下标
{
	int mid = Getmidindex(arr, left, right);
	swap(&arr[mid], &arr[right]);
	int key = arr[right];//将基准值保存,基准值的位置就行出一个坑
	while (left < right)
	{
		while (left < right && arr[left] <= key)//同理找大于基准值
			left++;
		arr[right] = arr[left];//把大于基准值的值填在坑中
		while (left < right && arr[right] >= key)
			right--;
		arr[left] = arr[right];
	}
	arr[left] = key;//最后的坑就是基准值的位置
	return left;
}

为了方便理解,我将于图解的形式讲解

动态过程如上图

3.前后指针

个人认为最好理解的方法

int PartSort3(int* arr, int left, int right)//快速排序之前后指针法,返回值为key的下标
{
	int mid = Getmidindex(arr, left, right);
	swap(&arr[mid], &arr[right]);
	int key = arr[right];
	int cur = 0;
	int prev = cur - 1;//其实就是从0到prev所有下标对应的值都小于基准值,所有一开始我们初始化不能为0
	while (cur <= right)
	{
		if (arr[cur] < key)//找到一个比基准值小的值就++prev
			swap(&arr[++prev], &arr[cur]);
		cur++;
	}
	swap(&arr[++prev], &arr[right]);
	return prev;
}

总结

以上就是用递归来实现快排的三种方式,下一篇文章我们将讲解非递归来实现快排。

觉得还不错就点个小小的赞吧


 

标签:arr,right,递归,基准值,int,三种,排序,left
From: https://blog.csdn.net/Su_han_dg/article/details/143832538

相关文章

  • 弦有三种选择
    注:主题为二选一,解读仅供参考。理解单字主题的角度可自行选择。1.旅鸟焚其巢,旅人先笑,后号咷。——《易经•火山旅》何为旅?也许是为了追寻珍贵之物,远游天涯;也许是要从困境中脱身,暂时休息;也许旅行就是生活本身。有很多作品与旅有关,《在路上》的邈远,《魔女之旅》的明亮,《少女终末......
  • 快速排序
    #include<iostream>usingnamespacestd;constintN=1e6+10;inta[N],n;voidquick_sort(inta[],intl,intr){ if(l>=r)return; intx=a[l+r+1>>1],i=l-1,j=r+1;//防止r,l都为0而出错:l+r+1>>1 while(i&l......
  • 归并排序
    先递归为多个小部分再进行排序#include<iostream>usingnamespacestd;constintN=1e5+10;inta[N],tem[N];voidmerge_sort(inta[],intl,intr){ if(l>=r)return; intmid=l+r>>1; merge_sort(a,l,mid),merge_sort(a,mid+1,r);//......
  • mybatis 中 foreach collection的常见错误和用法小结(三种)
    主要介绍了mybatis中foreachcollection的用法小结(三种),需要的朋友可以参考下。foreach主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指......
  • 简单选择排序
     假设要排序的序列元素个数为n,简单选择排序的思路为:第一趟从第一个元素开始,在未排序的n个元素中选出最小元素,将其与序列第一个元素交换;第二趟从第二个元素开始,在未排序的n-1个元素中,选出最小元素,将其与本趟的第一个元素交换,以此类推,经过n-1趟,形成了从小到大的已排序序列。 ......
  • 一文带你了解防火墙的三种工作模式:路由模式、透明模式(网桥)、混合模式。网络安全零基础
    防火墙作为网络安全的核心设备之一,扮演着至关重要的角色。它不仅能够有效防御外部网络的攻击,还能保护内部网络的安全。在如今复杂多样的网络环境下,防火墙的部署和工作模式直接影响着网络安全策略的实施效果。防火墙通常可以工作在三种模式下:路由模式、透明模式(网桥模式)以及......
  • 【C语言】函数递归
    1、递归的概念    其实我们在前面的学习中已经使用过函数的递归了。那么什么是递归呢    递归是一种解决问题的方法,就是函数自己调用自己,例如下面的函数。         上面就是一个简单的函数递归,在main函数内调用自己。2、递归的使用思路和......
  • python文件排序都有哪些方法
    在python环境中提供两种排序方案:用库函数sorted()对字符串排序,它的对象是字符;用函数sort()对数字排序,它的对象是数字,如果读取文件的话,需要进行处理(把文件后缀名‘屏蔽’)。(1)首先:我测试的文件夹是/img/,里面的文件都是图片,如下图所示:(2)测试库函数sorted(),直接贴出代码:impor......
  • c语言快速排序
    快速排序(Quicksort)是一种高效的排序算法,采用分治法(DivideandConquer)策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。快速排序的步骤:选择基准(Pivot):从数列中挑出一个元素,称为"基准"(pivot)。分区(Partitioning):重新排序数列,所有元素比基准值小的摆放......
  • 7.Java 注解和元注解(三种注解、四种元注解)
    一、注解概述注解也被称为元数据,用于修饰包、类、方法等数据信息和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息在JavaSE中,注解使用的目的比较简单,例如标记过时的功能,忽略警告等JavaEE中注解会充当更加重要的角色二、三种注......