交换排序--快速排序(就是太快,所以很重要)

发布于:2022-11-28 ⋅ 阅读:(399) ⋅ 点赞:(0)

  让你难过的事情,有一天,你一定会笑着说出来。


一.前言

  交换排序总思想:数据两两比较,发生逆序则交换,直到整个数据有序。交换排序又分为冒泡排序快速排序。本文讲述有关快速排序的知识。


二.快速排序思想

基本思想:
  如果要将一组数据从小到大进行排序,通过一趟排序,将待排序记录分割成独立的两部分,前部分数据都比后部分的数据小,再分别对这两部分进行排序(分治法的思想),以达到整个序列有序。
  举个例子:
在这里插入图片描述
  假设有如上的一组数据,蓝色代表中间数据,绿色代表比蓝色小的数据,红色代表比蓝色大的数据。通过一趟快速排序,绿色将会全部在蓝色的左边,红色将会全部在蓝色的右边,如下:
在这里插入图片描述
  蓝色就将这组数据分成独立的两部分,其左边的数据(绿色)都比其又变的数据(红色)小。
  那是如何达到上诉效果的呢?就是依次将其它数据和我们选择的中间数据比较,小的就放到它的前面,大的就放到它后面。


三.过程分析

操作过程:
1. 任取一元素(如:第一个)为中心(pivot)轴
2. 所有比中心轴小的元素一律前放,比中心轴大的元素一律后放,这样就会形成左右两个子序列
3. 对各子序列重新选择中心元素并依上述规则调整(递归思想)
4. 直到每个子序列的元素只剩一个

快速排序图解:
  有如下的一组数据(图形下面的数字代表数组下标),现在需要将其按从小到大进行排序。
在这里插入图片描述
  任取一个数据为中心轴。这里选取第一个数据为中心轴,将该位置的数据进行拷贝(拷贝后假设该位置没有数据,方便分析),外加两个指示位置的指示指针low与high,low初始指向被拷贝数据的位置,即中心轴数据的位置,high指向这组数据的最后一个数据,如下:
在这里插入图片描述

  此时low所指示的位置没有数据,需要从low与high之间选取一个比中心轴数据(19)小的数据放到该位置。high所指的5号位置25比中心轴数据大,high移动到4号位置,如下:
在这里插入图片描述
  所指的四号位置数据比中心轴数据(19)小,则将high所指的4号位置的数据拷贝到low所指的0号位置,如下:
在这里插入图片描述

  现在high所指的位置没有数据,需要从low与high两者之间选取一个比中心轴数据(19)大的数据放到high所指的位置。low所指的0号位置8比中心轴数据小,不满足则将low往前移动一个位置,如下:
在这里插入图片描述
  再比较low所指的当前位置,满足进行交换,如下:
在这里插入图片描述

  接下来还是按照上面的操作进行,从两者之间选取比中心轴数据小的放到low所指的位置,30比19大,不满足,high往往后移动一个位置,如下:
在这里插入图片描述
  再与high所指的当前位置进行比较,满足进行交换,如下:
在这里插入图片描述

  此时high的位置为空,从两者之间选取比中心轴数据(19)大的放到high的位置,13<19,不满足,low往前移动一个位置,如下:
在这里插入图片描述
  再与low所指的当前位置进行比较,满足进行交换,如下:
在这里插入图片描述
  此时low的位置又为空,从两者之间选取比中心轴数据(19)小的放到low的位置,49>19,不满足,high往后移动一个位置,如下:
在这里插入图片描述
  当low与high重合即相等的时候,本趟排序结束。此时它们所指的位置,即为中心轴数据的插入位置,用红色标记如下:
在这里插入图片描述
  这样就形成了以中心轴为分界线的左右两个子序列,对各子序列调用上述同样的操作,包括重新选取中心轴元素等,就不重复演示了,步骤都是一样的。

总结:
·对于快速排序都是递归调用同样的操作,则可以用递归算法;
·high于low重合时所指位置即为中心轴数据的位置;
·当各子序列只有一个元素的时候,即排序完成。


四.代码实现

  对于快速排序的算法用递归思想来实现。
递归开始结束的条件是: 只有一个元素的时候递归开始结束;
本级递归要为上一级递归返回什么: 返回完成本趟排序后中心轴数据的位置;
递归要完成的任务是: 将比中心轴数据小的移动到其前面,大的移动到其后面。

FastSort函数:

typedef int ElementType;
void FastSort(ElementType array[], int low, int high)
{
	int pivotPos;//中心轴位置
	if (low < high)//子序列元素大于一个,则进行递归调用
	{
		pivotPos = FindPivotPosition(array, low, high);//对数据进行交换并返回中心轴数据位置的功能函数
		FastSort(array, low, pivotPos - 1);//递归左子序列
		FastSort(array, pivotPos + 1, high);//递归右子序列
	}
}

FindPivotPosition函数:

typedef int ElementType;
int FindPivotPosition(ElementType array[], int low, int high)//对数据进行交换,并返回中心轴数据
{
	ElementType pivotKey;//中心轴关键字的值
	pivotKey = array[low];//选取第一个数据作为中心轴关键字的值
	while (low < high)//当low于high重合时,本轮结束
	{
		while (low < high&&array[high]>=pivotKey)//起初low所指位置没有有效数据,要从后面选取一个比中心轴数据小的数据放到low所指位置
		{   
			high--;//不满足则high要往后移动一个位置
		}
		array[low] = array[high];//满足则进行交换
		while (low < high&&array[low]<=pivotKey)//此时high所指位置没有有效数据,要从前面选取一个比中心轴数据大的数据放到high所指的位置
		{
			low++;//不满足则让low往前移动一个位置
		}
		array[high] = array[low];//满足则进行交换
	}
	array[low] = pivotKey;//将中心轴数据插入到high与low重合的位置
	return low;//返回交换完成后中心轴数据的位置
}


//补充:利用递归方式,实现快排
void FastSort(int* nums, int low, int high)
{
	//两个哨兵
	int i = low;
	int j = high;
	int temp;//临时变量用于交换数据
	int pivortKey = nums[low];//中心轴数据
	if (low > high)return;//递归结束的条件
	while (i < j)
	{
		while (i<j && nums[j]>=pivortKey)j--;//在右边寻找一个比中心轴数据小的元素
		while (i < j && nums[i] <= pivortKey)i++;//在左边寻找一个比中心轴数据大的元素
		if (i < j)//当寻找到了满足元素的两个哨兵位置
		{
			temp = nums[i];
			nums[i] = nums[j];
			nums[j] = temp;
		}
	}
	//当两个哨兵相遇时
	nums[low] = nums[i];
	nums[i] = pivortKey;
	//递归遍历
	FastSort(nums, low, i - 1);
	FastSort(nums, i + 1, high);
	return;
}

五.总结

1.快速排序时间复杂度为O(nlogn),FastSort为O(logn),FindPivotPosition为O(n);
2.就平均效率而言快速排序是内部排序方法中效率最好的一个;
3.快速排序不是原地排序,由于程序中使用了递归,需要递归调用栈的支持,而栈的长度取决于递归调用的深度。(即使不用递归,也需要使用用户栈);
4.快速排序是一种不稳定的排序方法;
5.快速排序不适于对原本有序或基本有序的记录序列进行排序,这样会退化为冒泡排序。


  希望对大家有帮助,我是老胡,感谢阅读!!❤️ ❤️

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到