Bootstrap

用C++ 实现快速排序

快速排序是公认的排序之王。之前在学习排序算法时,我经常一遍遍的“手撕”快速排序代码,无论用递归方法还是非递归方法,我都毫无感觉,以至于我以为它已经刻在我脑子里了,不用思考就能默写。后来用了sort方法后,觉得实在太方便了,就很久没写快排实现的代码了,,终于有一天耳朵里传进一个声音“ 同学,写一个快排的代码吧 ”,,我,竟然栽在快排上了!!

经过此次痛苦的教训,我立马复习了快排的三种方法(以排升序为例,且“基值”为a[begin]),如下:

  1. 挖坑法(需要单独记录,否则被覆盖):先选一个数据a[key](这里是a[begin]),用k保存a[key]的值,并在key处留有一个坑,右边end指针向左找比k小的值补左坑位(可直接覆盖),再左边begin指针向右找比k大的值补右坑位,直到end=begin停止,此时用k补坑位。(若选begin值为“坑位”就先从右边找合适的值补坑,若选end值为“坑位”则先从左边找值去补坑)。—时间复杂度:O(NlogN)

  2. hoare的直接排序(无需单独记录):以最左边的值k为“基值”划分。end向左找到比k小的值停下,begin向右找到比k大的值停下,将begin找到的值与end找到的值进行交换,直到end=begin此时交换k和end指针的值即可。—时间复杂度:O(NlogN)

  3. 前后指针法:令k=a[key],key=begin(或者end)。用prev指向序列开头即k,cur指向k的下一个值。cur向后找到比k小的值停下,然后prev先后移一位再交换prev与cur的值;cur继续向后直到cur指向NULL为止,最后交换prev和k即可。 —时间复杂度:O(NlogN)

关于快排更多的详细内容可参考博客【快速排序的思想

以下是“挖坑法”和“左右部分排序”用C++的实现代码~

#include <iostream>
#include <vector>
using namespace std;

void quickSort(vector<int> &num, int left, int right)     //挖坑法
{
	if (left >= right)     //先检查左右条件
		return;
	int i = left, j = right, x = num[left];   //选择最左边的值为坑位
	while (i < j) {
		while (i < j && num[j] >= x)//从右向左找到第一个小于x的
			j--;
		if (i < j)
			num[i++] = num[j];//填坑之后,查找下一位
		while (i < j && num[i] <= x)//从左向右找第一个大于x的数
			i++;
		if (i < j)
			num[j--] = num[i];
	}
	num[i] = x;     //把最开始取出来的值放到新坑位
	quickSort(num, left, i - 1);//以i为中间值,分左右两部分递归调用
	quickSort(num, i + 1, right);
}

void QuickSort(vector<int>& v,int left,int right)    //直接排序
{
	if (left>=right)  //当只有一个数据或者序列不存在时,不用操作
		return ;
	
	int key = left;        //以左边的第一个数为基值
	int end = right;
	while (left<right)
	{
		while (left<right&&v[right] > v[key])   //先从右向左找小于key的
			{   right--;   }
		while (left<right&&v[left] <= v[key])  //再从左向右找大于key的
			{   left++;   }
			if (left < right)
		{   swap(v[left], v[right]);    }    //找到left和right后交换两个值
	}
	swap(v[left], v[key]);   //left== right ,将基值与相遇点的值交换
	int meet= left;     //划分开基值的左右部分
	
    QuickSort(v, key, meet-1);   //对左序列递归排序
	QuickSort(v, meet+1, end);  //对右右序列递归排序
}


int main()
{
	vector<int> v1 = {1,3,6,4,5,8,2};
	vector<int> v2 = {11,21,13,5,32,88,9};
	quickSort(v1,0,v1.size()-1);
	cout<<"v1通过“挖坑法”排序的结果是:     ";
	for (auto &e : v1)
		cout <<e<< " ";
	QuickSort(v2,0,v2.size()-1);
	cout<<endl<<"v2通过“左右指针法”排序的结果是:  ";
	for (auto &e : v2)
		cout <<e<< " ";
	return 0;
}

运行结果如下:

在这里插入图片描述

我之前的博客【八种排序算法思想】中写到其他算法的思想以及代码的实现,有兴趣的可以点击查看。最后再次感叹,这些基础千万不要小瞧啊~

;