当前位置:   article > 正文

排序算法——快速排序(图解+代码)_快速排序算法

快速排序算法


快速排序

定义数组的头部为一个基准,首先从基准的右边比较,交换基准数字;然后从基准的左边比较,交换基准数字。
使基准的左右两边分别都是比基准小和比基准大的数字,完成一次排序。
然后从左右两边分别重新定义新的基准,继续比较排序。
持续减少比较长度,直至左右两边均剩余一个数字,此时完成整个数组的排序。

  • 从小到大进行排序
  • 时间复杂度O( nlog2n )
  • 空间复杂度O( log2n ),不稳定(数据跳跃)
  • 一次快速排序,时间复杂度O(n),递归函数的时间复杂度O( log2n )
  • 数组本身有序,时间复杂度变为O(n2),退化成选择排序

1 一次快速排序的过程

1.1 图解

  • 1、定义一个基准tmp,每次都将下标low的值即arr[low],设定为基准值。
  • 2、首先从下标high开始比较,一直到下标low。
    • 如果arr[high]大于等于基准tmp,且下标low小于下标high,将high向前移动。
    • 如果arr[high]小于基准tmp,将下标high的值arr[high]置于下标low的位置上。
    • 当下标low等于下标high时,说明下标low的右边都是比基准tmp大的数字,此时右边完成交换。
  • 3、然后从下标low开始比较,一直到下标high。
    • 如果arr[low]小于等于基准tmp,且下标low小于下标high,将low向后移动。
    • 如果arr[low]大于基准tmp,将下标low的值arr[low]置于下标high的位置上。
    • 当下标low 等于下标high时,说明下标low的左边都是比基准tmp小的数字,此时左边完成交换。
  • 4、然后将基准值tmp置于下标low的位置上,归位,完成数值交换。此时基准值的两边都是比基准值小或比基准值大的数字


    在这里插入图片描述

1.2 C语言实现

static int Partition(int* arr,int low,int high)//一次快速排序,时间复杂度O(n)
{
	int tmp = arr[low];//备份基准值

	while (low < high)//当low大于等于high时,结束循环
	{
		while (low < high && arr[high] >= tmp)//从最后面high开始到low之间,寻找比基准值tmp小的数字,将其移动到前面的空缺位上
		{
			high--;//如果arr[high]大于等于基准tmp,向前移动
		}
		if (low == high)//当low和high相等时说明没有比基准tmp小的数字,跳出整个循环
		{
			break;
		}
		else//否则,说明arr[high]小于基准tmp,将high的值置于low的位置上
		{
			arr[low] = arr[high];
		}

		while (low < high && arr[low] <= tmp)//从最前面low开始到high之间,寻找比基准值tmp大的数字,将其移动到后面的空缺位上
		{
			low++;//如果arr[low]大于等于基准tmp,向后移动
		}
		if (low == high)//当low和high相等时说明没有比基准tmp大的数字,跳出整个循环
		{
			break;
		}
		else//否则,说明此位置的arr[low]大于基准tmp,将low的值置于high的位置上
		{
			arr[high] = arr[low];
		}
	}

	arr[low] = tmp;//最后将基准值tmp,归位,此时基准值的两边都是比基准值小或比基准值大的数字

	return low;//返回基准值的位置,用于判断边界
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

2 快速排序(递归)

2.1 图解

  • 首先进行一次快速排序
  • 然后分别判断下标 par(即,基准值所在的下标low) 在整个数组的左右两边的数字个数
    • 如果左右两边剩余的数字个数大于1,就根据下标par给定新的low和high,继续进行左右两边的快速排序。
    • 直至左右两边均剩余一个数字,此时完成整个数组的排序。


      在这里插入图片描述

3.2 C语言实现

static void Quick(int* arr, int low, int high)//排序边界,递归
{
	int par = Partition(arr, low, high);
	if (low + 1 < par)//继续排序划分,直至左边剩余1位数字
	{
		Quick(arr, low, par - 1);
	}
	if (par < high - 1)//继续排序划分,直至右边剩余1位数字
	{
		Quick(arr, par + 1, high);
	}
}

void QuickSort(int* arr, int len)//快速排序(递归)
{
	Quick(arr, 0, len-1);//调用接口,参数列表不同
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3 快速排序(非递归)

3.1 图解

  • 首先创建一个大小为4个整型数字的数组缓冲区,用于保存每一次快速排序后,新的下标low和下标high,初始化数组下标top为0
  • 将下标low和high置于数组的头部和尾部,即0和len-1,执行一次快速排序
  • 然后分别判断下标 par(即,基准值所在的下标low) 在整个数组的左右两边的数字个数,并分别根据下标par给定新的low和high,存入数组缓冲区中
  • 然后依次从缓冲区读取新的low和high,继续进行左右两边的快速排序。
  • 直至左右两边均剩余一个数字,此时数组缓冲区下标越界,说明已完成整个数组的排序。

创建一个大小为4个整型数字的数组缓冲区
因为:每次最多进两组数据,即1个基准的左边和右边都存在超过1个数字需要排序,之后读出数据后再存放数据会直接覆盖,这样可以优先将基准一边的数据先处理完,然后再读出数据处理另一边。

在这里插入图片描述

3.2 C语言实现

void QuickSort(int* arr, int len)//快速排序
{
	int buff[4];//每次最多进两组数据即,1个基准的左边和右边都存在超过1个数字需要排序,之后读出数据后再存放数据会直接覆盖
	int* stack = buff;
	assert(stack != NULL);
	int top = 0;//栈顶指针,当前可以存放数据的下标

	int low = 0;
	int high = len - 1;
	int par = Partition(arr, low, high);

	while (top >= 0)
	{
		if (low + 1 < par)
		{
			stack[top++] = low;
			stack[top++] = par - 1;
		}
		if (par < high - 1)
		{
			stack[top++] = par + 1;
			stack[top++] = high;
		}

		high = stack[--top];
		low = stack[--top];

		if (top < 0)
		{
			break;
	    }

		par = Partition(arr, low, high);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/640409
推荐阅读
相关标签
  

闽ICP备14008679号