快速排序-C++实现

快速排序

简介
快速排序是对冒泡排序的一种改进, 它是不稳定的。由C. A. R. Hoare在1962年提出的一种划分交换排序,采用的是分治策略(一般与递归结合使用),以减少排序过程中的比较次数,它的最好情况为O(nlogn),最坏情况为O(n^2),平均时间复杂度为O(nlogn)。

基本思想
选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小。然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以达到全部数据变成有序。

步骤
(1) 从数列中挑出一个基准值。
(2) 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边),在这个分区退出之后,该基准就处于数列的中间位置。
(3) 递归地把基准值前面的子数列和基准值后面的子数列进行排序。

注意:基准元素/左游标/右游标都是针对单趟排序而言的, 也就是说在整个排序过程的多趟排序中,各趟排序取得的基准元素/左游标/右游标一般都是不同的。对于基准元素的选取,原则上是任意的,但是一般我们选取数组中第一个元素为基准元素(假设数组随机分布)。
算法步骤(图示样例)

  • 举个测试例子

  • 在这里插入图片描述

  • 该例子完整的算法过程在这里插入图片描述

  • 递归方法

  //快排的递归方法
  int parition(int* br, int left, int right) {
  	int tmp = br[left];
  	while (left < right) {
  		while (tmp <= br[right] &&left<right) --right;
  		if (left < right) br[left] = br[right];
  		while (tmp > br[left] && left <right) ++left;
  		if (left < right) br[right] = br[left];
  	}
  	br[left] = tmp;
  	return left;
  }
  void recursion(int* ar, int left, int right) {
  	if (left < right) {
  		int pos = parition(ar, left, right);
  		recursion(ar, left, pos - 1);
  		recursion(ar, pos + 1, right);
  	}
  }
  void quick_sort1(int* br, int left, int right) {
  	if (br == nullptr || left >= right) return;
  	recursion(br, left, right);
  }
  • 非递归方法(用队列去存储原来递归过程中产生的范围值)
  /*
  快排的非递归
  非递归就是用循环去模拟递归过程,这个时候就必须十分熟悉递归调用的具体过程
  */
  //方法1
  void  un_recursion2(int* ar, int left, int right) {
  	queue<pair<int,int>> qu;
  	qu.push(pair<int, int>(left, right));//首先保证队列中至少有一组数据
  	while (!qu.empty()) {
  		int i = qu.front().first;
  		int j = qu.front().second;
  		qu.pop();
  		int pos = parition(ar, i, j);
  		if (i < pos-1) {
  			qu.push(pair<int,int>(i, pos - 1));
  		}
  		if (pos + 1 < j) {//紧接着添加就是为了使队列中在左边划分完成的时候,队列中还能够保存有初始状态的右边的起始数值
  			qu.push(pair<int, int>(pos + 1, j));
  		}
  	}
  }
  //方法2
  void un_recursion1(int* ar, int left, int right) {
  	queue<int> q;
  	q.push(left);
  	q.push(right);
  	while (!q.empty()) {
  		int i = q.front();
  		q.pop();
  		int j = q.front();
  		q.pop();
  		int pos = parition(ar, i, j);
  		if (i < pos) {
  			q.push(i);
  			q.push(pos - 1);
  		}
  		if(pos+1<j){
  			q.push(pos+1);
  			q.push(j);
  		}
  	}
  }
  void quick_sort2(int* br, int left, int right) {
  	if (br == nullptr || left >= right) return;
  	//un_recursion1(br, left, right);
  	un_recursion2(br, left, right);
  }
  • 随机划分(随机找到一个数值为参照物)
 //快排的划分函数的参照物数值的随机取值
  int parition(int* br, int left, int right) {
  	int tmp = br[left];
  	while (left < right) {
  		while (tmp <= br[right] &&left<right) --right;
  		if (left < right) br[left] = br[right];
  		while (tmp > br[left] && left <right) ++left;
  		if (left < right) br[right] = br[left];
  	}
  	br[left] = tmp;
  	return left;
  }
  int ran_partition(int* br, int left, int right) {
  	srand(time(nullptr));
  	int rnd = rand() % (right - left + 1) + left;
  	/*+1是为了得到范围内的最大长度,+left是为了得到
  	一定是交换范围里面的随机值,即绝对位置而不是相对位置*/
  	swap(br[left], br[rnd]);
  	return partition(br, left, right);
  }
  void quick_sort3(int* br, int left, int right) {
  	if (left < right) {
  		int pos = ran_partition(br, left, right);
  		quick_sort3(br, left, pos - 1);
  		quick_sort3(br, pos + 1, right);
  	}
  }
  • 三位取中划分(找到范围内的中位数与左边界交换后然后再以左边界的值为参照物然后划分)
  //快排的划分函数的参照物数值的三位取中方法取值
  int parition(int* br, int left, int right) {
  	int tmp = br[left];
  	while (left < right) {
  		while (tmp <= br[right] &&left<right) --right;
  		if (left < right) br[left] = br[right];
  		while (tmp > br[left] && left <right) ++left;
  		if (left < right) br[right] = br[left];
  	}
  	br[left] = tmp;
  	return left;
  }
  int mid_partition(int* br, int left, int right) {
  	int mid = (right + left) / 2;
  	struct node {
  		int index;
  		int value;
  		operator int()const {//重载一个强转运算符,
  		//为了使得使用优先队列排序的时候能够比较的是数值而不是下标
  			return value;
  		}
  	};
  	
  	struct node ln = { left,br[left] };
  	struct node mn = { mid,br[mid] };
  	struct node rn = { right,br[right] };
  	priority_queue<node> pque;
  	pque.push(ln);
  	pque.push(mn);
  	pque.push(rn);
  	pque.pop();//弹出来一个,那么剩下的队头的就是中位数的结点
  	swap(br[left], br[pque.top().index]);
  	return partition(br, left, right);
  }
  void quick_sort4(int* br, int left, int right) {
  	if (left < right) {
  		int pos = mid_partition(br, left, right);
  		quick_sort4(br, left, pos - 1);
  		quick_sort4(br, pos + 1, right);
  	}
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LredCoat

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

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

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

打赏作者

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

抵扣说明:

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

余额充值