数据结构 八大排序之快速排序

快速排序

快速排序,说白了就是给基准数据找其正确索引位置的过程

1.1快速排序引入

希尔排序相当于直接插入排序的升级,他们属于插入排序类;堆排序相当于简单选择排序的升级,他们同属于选择排序类;而对于交换排序类的冒泡排序升级版本就是快速排序

1.2快速排序的基本思想

通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个排序的目的。

1.3快速排序的排序流程

  1. 首先设定一个分界值,通过该分界值将数组分成左右两部分。
  2. 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
  3. 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
  4. 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

总结来说:就是分治+填数

1.4实例说明

以12、10、8、22、5、13、28、21、11我们要将它按从小到大排序排序过程:
在这里插入图片描述
详细过程:

  1. 设定两个指针 left 和 right,它们初始分别指向待排序序列的左端和右端;此外还要附设一个基准元素 tmp(一般选取第一个,本例中基准tmp的值为 20)。
    在这里插入图片描述

  2. 首先从 right 所指的位置从右向左搜索找到第一个小于 tmp 的元素,然后将其记录在基准元素所在的位置。
    在这里插入图片描述

  3. 接着从 left 所指的位置从左向右搜索找到第一个大于 tmp的元素,然后将其记录在 right 所指向的位置。
    在这里插入图片描述

  4. 然后再从 right 所指向的位置继续从右向左搜索找到第一个小于 tmp 的元素,然后将其记录在 left 所指向的位置。
    在这里插入图片描述

  5. 接着,left 继续从左向右搜索第一个大于 tmp的元素,如果在搜索过程中出现了 left == right ,则说明一趟快速排序结束。此时将 tmp 记录在 left 和 right 共同指向的位置即可。
    在这里插入图片描述
    以上便是一轮快速排序的详细过程

注意:

  • 向下划分至少需要这个组两个数据,才有必要划分,0个或者1个都没有必要
  • 划分时:从右向左找比基准小的(相等)
  • 从左向右找比基准值大的

1.5代码实现

//一次划分函数  核心函数  //返回基准值最终所在下标
int Partition(int *arr, int left, int right)
{
	//先讲arr数组里的[left, right]的第一个值 作为基准值
	int tmp = arr[left];

	while(left < right)
	{
		while(left<right && arr[right] > tmp)//左右边界没有相遇且当前右边的值大于基准值tmp
		right--;

		if(left < right)//如果此时,左右边界没有相遇,那就只能证明右边right找到了一个小于等于基准值tmp的值
		{
			arr[left] = arr[right];
		}
		else
		{
			break;
		}
		

		while(left<right && arr[left] <= tmp)//左右边界没有相遇且当前左边的值小于等于基准值tmp
		left++;

		if(left < right)//如果此时,左右边界没有相遇,那就只能证明左边left找到了一个大于基准值tmp的值
		{
			arr[right] = arr[left];
		}
		else
		{
			break;
		}
		
	}

	arr[left] = tmp;//此时 因为 left == right
	return left;//return right ok
}

void Quick(int *arr, int left, int right)
{
	if(left < right)//通过left <right  保证[left, right]这个范围内至少两个数据
	{
		int par = Partition(arr, left, right);

		if(left < par-1)//基准值左半部分  至少有两个值才有必要去递归
		{
			Quick(arr, left, par-1);
		}
		if(par+1 < right)//基准值右半部分  至少有两个值才有必要去递归
		{
			Quick(arr, par+1, right);
		}
	}

}
void QuickSort(int *arr, int len)
{
	Quick(arr, 0, len-1);
}

1.6性能分析

越乱越快,越有序越慢

  1. 时间复杂度:
    最优情况:O(nlogn)每次数据元素都能平均的分成两个部分。得到一个完全二叉树;
    最坏情况: O(n^2)这个数仅有右子树或左子树,比较次数为 (n-1)+(n-2) + (n-3) + … +1=n*(n-1)/2 ;
    平均情况:O(nlogn)。
  2. 空间复杂度:O(1)。
  3. 稳定性:因为关键字的比较和交换是跳跃进行的,会改变数据元素的相对位置;因此,快速排序是一种不稳定的排序方法,但是也是内排序中平均效率最高的排序算法。

(小白一位,如有错误欢迎指正)

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
数据结构中的八大排序算法,是指常见的八种用于对数据进行排序的算法。这八种算法分别是冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序和基数排序。 冒泡排序是一种简单的排序算法,通过不断比较和交换相邻元素的位置,使得最大(或最小)的元素逐渐往后(或往前)移动。 选择排序是一种简单直观的排序算法,每次选择未排序序列中最小(或最大)的元素,放到已排序序列的末尾。 插入排序是一种简单直观的排序算法,将一个待排序的元素插入到已部分排序的数列中的合适位置。 希尔排序是一种改进的插入排序算法,通过将待排序数列分组,并对每个分组进行插入排序,然后逐渐减小分组规模,最后进行一次插入排序。 归并排序是一种分治思想的排序算法,将待排序数列不断分割成较小的数列,然后再将这些较小的数列按照顺序进行合并。 快速排序是一种分治思想的排序算法,通过选择一个中间的基准元素,将数列分割成两部分,然后分别对这两部分进行排序。 堆排序是一种利用堆这种数据结构排序算法,通过将待排序数列构建成一个大(或小)顶堆,然后逐步将堆顶元素与最后一个元素交换,并调整堆结构。 计数排序是一种非比较型的排序算法,通过统计待排序数列中每个元素出现的次数,然后依次输出即可。 基数排序是一种非比较型的排序算法,通过对待排序数列的每个位进行排序,依次从低位到高位进行。 这里简单介绍了八大排序算法的基本思想和实现方法。在实际应用中,不同的排序算法适用于不同的场景和要求,我们需要根据具体情况选择合适的算法
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mi ronin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值