1、取最后一个元素作为中轴的快排
#include <bits/stdc++.h>
using namespace std;
int PartSort(int *arr, int left, int right) {
/// 取数组中的最后一个元素作为中轴,&key相当于就是给arr[right]取一个别名。
/// key和arr[right]指向的是同一个内存地址。
int &key=arr[right];
while(left<right) { /// 当left>=right的时候就退出。
/// 下面的左右两次遍历一定是先从左向右,再从右向左,因为是以最后一个元素作为基准。
/// 如果是选择第一个元素作为基准,那么遍历的顺序应该反过来。
while(left<right&&arr[left]<=key) {
left++;
}
while(left<right&&arr[right]>=key) {
right--;
}
/// 交换选出来的左边比中轴元素大,右边比中轴元素小这两个元素。
swap(arr[left], arr[right]);
}
/// 将一趟快排中的中轴元素放到他应该放入的位置。
swap(arr[left], key);
return left; /// 返回一趟快排之后的中轴元素最终的位置。
}
void QuickSort(int *arr, int left, int right) {
/**
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>
void assert( int expression );
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
然后通过调用 abort 来终止程序运行。
*/
assert(arr); /// 如果arr为空的数组的话会调用abort来终止程序。
if(left>=right) { /// 递归终止条件。
return;
}
int index=PartSort(arr, left, right);
/// 每一次快排都会确定一个元素在数组中最终的位置。
QuickSort(arr, left, index-1);
QuickSort(arr, index+1, right);
}
int main() {
int arr[100005];
int n;
scanf("%d", &n);
for(int i=0;i<n;i++) {
scanf("%d", &arr[i]);
}
QuickSort(arr, 0, n-1);
for(int i=0;i<n;i++) {
printf("%d:%d\n", i, arr[i]);
}
return 0;
}
上面代码中的一趟快排还有另一种写法。
int PartSort(int* arr,int left,int right) {
int key = arr[right]; /// 选取最后一个元素作为中轴,并将它先保存在变量key中。
while(left < right) {
while(left < right && arr[left] <= key) {
++left;
}
arr[right] = arr[left];
while(left < right && arr[right] >= key) {
--right;
}
arr[left] = arr[right];
}
/// 下面的代码left和right应该都是一样的。
arr[right] = key;
return right;
}
2、采用三轴取中的方法对快排进行优化。
#include <bits/stdc++.h>
using namespace std;
/// 三数取中
int GetMid(int* arr,int left,int right)
{
assert(arr);
int mid = left + ((right - left)>>1);
if(arr[left] <= arr[right])
{
if(arr[mid] < arr[left])
return left;
else if(arr[mid] > arr[right])
return right;
else
return mid;
}
else
{
if(arr[mid] < arr[right])
return right;
else if(arr[mid] > arr[left])
return left;
else
return mid;
}
}
int PartSort(int* arr,int left,int right) {
int mid = GetMid(arr,left,right); /// 找出三个数中大小在中等的那个数的下标。
swap(arr[mid],arr[right]); /// 将选出来的中等的数与最后一个数继续交换,就可以直接套用之前的以最后一个元素为中轴的快排了。
int& key = arr[right]; /// 给arr[right]取一个别名为key,两者指向同一个内存空间。
while(left < right)
{
while(left < right && arr[left] <= key)/// 因为有可能有相同的值,防止越界,所以加上left < right
++left;
while(left < right && arr[right] >= key)
--right;
swap(arr[left],arr[right]);
}
swap(arr[left],key);
return left;
}
void QuickSort(int *arr, int left, int right) {
/**
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
#include <assert.h>
void assert( int expression );
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
然后通过调用 abort 来终止程序运行。
*/
assert(arr); /// 如果arr为空的数组的话会调用abort来终止程序。
if(left>=right) { /// 递归终止条件。
return;
}
int index=PartSort(arr, left, right);
/// 每一次快排都会确定一个元素在数组中最终的位置。
QuickSort(arr, left, idx-1);
QuickSort(arr, idx+1, right);
}
int main() {
int arr[100005];
int n;
scanf("%d", &n);
for(int i=0;i<n;i++) {
scanf("%d", &arr[i]);
}
QuickSort(arr, 0, n-1);
for(int i=0;i<n;i++) {
printf("%d:%d\n", i, arr[i]);
}
return 0;
}
3、快排的非递归实现
#include <bits/stdc++.h>
using namespace std;
int PartSort(int *arr, int left, int right) {
/// 取数组中的最后一个元素作为中轴,&key相当于就是给arr[right]取一个别名。
/// key和arr[right]指向的是同一个内存地址。
int &key=arr[right];
while(left<right) { /// 当left>=right的时候就退出。
while(left<right&&arr[left]<=key) {
left++;
}
while(left<right&&arr[right]>=key) {
right--;
}
/// 交换选出来的左边比中轴元素大,右边比中轴元素小这两个元素。
swap(arr[left], arr[right]);
}
/// 将一趟快排中的中轴元素放到他应该放入的位置。
swap(arr[left], key);
return left; /// 返回一趟快排之后的中轴元素最终的位置。
}
void QuickSortNotR(int* arr,int left,int right) {
assert(arr);
stack<int> s; /// 定义一个栈,用来模拟递归。
/// 初始的时候将数组边界【0和n-1】压入栈中。先压入左区间还是右区间都可以,
/// 只是取出栈的顺序不同,下面的代码要做相应的变化。
s.push(left);
s.push(right); /// 后入的right,所以要先拿right
while(!s.empty()) { ///栈不为空
/// 取出要进行一趟快排的左右区间。
int right = s.top();
s.pop();
int left = s.top();
s.pop();
/// 进行一趟快排。
int index = PartSort(arr,left,right);
/// 如果进行一趟快排之后中轴左边的序列有超过一个元素,那么就要进行排序。
if((index - 1) > left) { ///左子序列
/// 将左右区间压入栈。
s.push(left);
s.push(index - 1);
}
/// 如果进行一趟快排之后中轴右边的序列有超过一个元素,那么就要进行排序。
if((index + 1) < right) { ///右子序列
/// 将左右区间压入栈。
s.push(index + 1);
s.push(right);
}
}
}
int main() {
int arr[100005];
int n;
scanf("%d", &n);
for(int i=0;i<n;i++) {
scanf("%d", &arr[i]);
}
QuickSortNotR(arr, 0, n-1);
for(int i=0;i<n;i++) {
printf("%d:%d\n", i, arr[i]);
}
return 0;
}