最简单的快排
void QSort(int arr[],int low,int high)
{
int first = low;
int last = high;
if (low>=high)
return;
//选择分割
int key = SelectPivot(arr,low,high);//选择选取序列的第一个元素作为基准
//一次分割
while (low < high)
{
while (high > low && arr[high]>=key)
{
high--;
}
arr[low]=arr[high];
while (high > low && arr[low]<=key)
{
low++;
}
arr[high]=arr[low];
}
arr[low]=key;//此时low=high,则把key放入low 或 high 均可
//本次分割结束把序列分成了两个序列,分别在两个序列上进行快排
QSort(arr,first,low-1);
QSort(arr,low+1,last);
}
int SelectPivot(int arr[],int low,int high)
{
return arr[low];//选择选取序列的第一个元素作为基准
}
随机化快排
/*快速排序,随机选择枢轴*/
void QSort(int arr[],int low,int high)
{
int first = low;
int last = high;
if (low >= high)
return;
//一次分割
int key = SelectPivotRandom(arr,low,high);//随机选择枢轴的位置
while(low < high)
{
while(high > low && arr[high] >= key)
{
high--;
}
arr[low] = arr[high];
while(high > low && arr[low] <= key)
{
low++;
}
arr[high] = arr[low];
}
arr[low] = key;
//一次分割结束
QSort(arr,first,low-1);
QSort(arr,low+1,last);
}
void swap(int& n,int& m)
{
int tmp = n;
n = m;
m = tmp;
}
/*随机选择枢轴的位置,区间在low和high之间*/
int SelectPivotRandom(int arr[],int low,int high)
{
//产生枢轴的位置
srand((unsigned)time(NULL));
int pivotPos = rand()%(high - low) + low;
//把枢轴位置的元素和low位置元素互换,此时可以和普通的快排一样调用划分函数
swap(arr[pivotPos],arr[low]);
return arr[low];
}
三数取中
void QSort(int arr[],int low,int high)
{
int first = low;
int last = high;
if (low >= high)
return;
//一次分割
int key = SelectPivotMedianOfThree(arr,low,high);//使用三数取中法选择枢轴
while(low < high)
{
while(high > low && arr[high] >= key)
{
high--;
}
arr[low] = arr[high];
while(high > low && arr[low] <= key)
{
low++;
}
arr[high] = arr[low];
}
arr[low] = key;
//分割结束
QSort(arr,first,low-1);
QSort(arr,low+1,last);
}
/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
int SelectPivotMedianOfThree(int arr[],int low,int high)
{
int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标
//使用三数取中法选择枢轴
if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
{
swap(arr[mid],arr[high]);
}
if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
{
swap(arr[low],arr[high]);
}
if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
{
swap(arr[mid],arr[low]);
}
//此时,arr[mid] <= arr[low] <= arr[high]
return arr[low];
//low的位置上保存这三个位置中间的值
//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}
void swap(int& n,int& m)
{
int tmp = n;
n = m;
m = tmp;
}
三数取中 + 结合插排 + 处理相等元素
void QSort(int arr[],int low,int high)
{
int first = low;
int last = high;
int left = low;
int right = high;
int leftLen = 0;
int rightLen = 0;
if (high - low + 1 < 10)
{
InsertSort(arr,low,high);
return;
}
//一次分割
int key = SelectPivotMedianOfThree(arr,low,high);//使用三数取中法选择枢轴
while(low < high)
{
while(high > low && arr[high] >= key)
{
if (arr[high] == key)//处理相等元素
{
swap(arr[right],arr[high]);
right--;
rightLen++;
}
high--;
}
arr[low] = arr[high];
while(high > low && arr[low] <= key)
{
if (arr[low] == key)
{
swap(arr[left],arr[low]);
left++;
leftLen++;
}
low++;
}
arr[high] = arr[low];
}
arr[low] = key;
//一次快排结束
//把与枢轴key相同的元素移到枢轴最终位置周围
int i = low - 1;
int j = first;
while(j < left && arr[i] != key)
{
swap(arr[i],arr[j]);
i--;
j++;
}
i = low + 1;
j = last;
while(j > right && arr[i] != key)
{
swap(arr[i],arr[j]);
i++;
j--;
}
QSort(arr,first,low - 1 - leftLen);
QSort(arr,low + 1 + rightLen,last);
}
/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
int SelectPivotMedianOfThree(int arr[],int low,int high)
{
int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标
//使用三数取中法选择枢轴
if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
{
swap(arr[mid],arr[high]);
}
if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
{
swap(arr[low],arr[high]);
}
if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
{
swap(arr[mid],arr[low]);
}
//此时,arr[mid] <= arr[low] <= arr[high]
return arr[low];
//low的位置上保存这三个位置中间的值
//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}
void swap(int& n,int& m)
{
int tmp = n;
n = m;
m = tmp;
}
//直接插入排序--小 到 大
void InsertSort(int arr[],int low,int high)
{
int i = 0;
int j = 0;
int key;//存放乱序的元素
for ( i = low + 1;i < high + 1;i++)
{
if (arr[i-1] > arr[i])
{
key = arr[i];
for ( j = i-1;j >= 0 && arr[j] > key;j--)
{
arr[j+1] = arr[j];
}
arr[j+1] = key;
}
}
}
注意:
1、检查数据是否已经排好序
//降序
for (int i = 0;i < len-1;i++)
{
assert(arr[i] >= arr[i+1]);//括号里面是正常情况下的状态
}
//升序
for (int i = 0;i < len-1;i++)
{
assert(arr[i] <= arr[i+1]);//括号里面是正常情况下的状态
}
2、上述代码是实现从小到大排序,如果是从大到小排序,则需要改变以下代码,其他不变
//从小到大
while(high > low && arr[high] >= key)
{
...
}
while(high > low && arr[low] <= key)
{
...
}
//从大到小
while(high > low && arr[high] <= key)
{
...
}
while(high > low && arr[low] >= key)
{
...
}