对上一篇博客进行拆分,修改
#include "iostream"
#include<stack>
using namespace std;
//快速排序
template <class T>
int QuickSort(T arr[], int begin, int end){
if (begin < end){
T temp = arr[begin];
//int i = begin;
//int j = end;
while (begin < end){
//当右边的数大于基准数时,略过,继续向左查找
//不满足条件时跳出循环,此时的j对应的元素是小于基准元素的
while (begin < end&&arr[end] >temp)
{
end--;
}
arr[begin] = arr[end];
//当左边的数小于等于基准数时,略过,继续向右查找
//(重复的基准元素集合到左区间)
//不满足条件时跳出循环,此时的i对应的元素是大于等于基准元素的
while (begin < end&&arr[begin] <= temp)
{
begin++;
}
arr[end] = arr[begin];
}
//此时i==j
arr[begin] = temp;
//QuickSort(arr, begin, i - 1);
//QuickSort(arr, i + 1, end);
return begin;
}
else
return 0;
}
//使用递归算法
template <class T>
void QuickSort1(T arr[], int begin, int end)
{
if (begin < end){
int mid = QuickSort(arr, begin, end);
QuickSort1(arr, begin, mid - 1);
QuickSort1(arr, mid + 1, end);
}
}
//使用非递归算法,即用栈来实现
/*第一步、申请一个栈,存放排序数组的起始位置和终点位置。
第二步、将整个数组的起始位置s和终点位置e进栈
第三步、出栈数据,对出栈的数据进行排序,查找基准数据所在最终的位置 p。
第四步、判断起始位置s 是否小于基准位置p - 1,如果小于则将起始位置和p - 1为终点位置进栈
第五步、判断基准位置p + 1 是否小于终点位置e,如果小于则将 p + 1作为起始位置,e作为终点位置进栈
第六步、判断栈是否为空,如果不为空则重复第三步,否则退出操作。*/
template<class T>
void QuickSort2(T arr[], int begin, int end){
stack<int> st;
if (begin < end){
int mid = QuickSort(arr, begin, end);
if (begin < mid - 1){
st.push(begin);
st.push(mid - 1);
}
if (mid + 1 < end){
st.push(mid + 1);
st.push(end);
}
// 其实就是用栈保存每一个待排序子串的首尾元素下标,
//下一次while循环时取出这个范围,对这段子序列进行QuickSort操作
while (!st.empty()){
int q = st.top();
st.pop();
int p = st.top();
st.pop();
mid = QuickSort(arr, p, q);
if (p < mid - 1){
st.push(p);
st.push(mid - 1);
}
if (mid + 1 < q){
st.push(mid + 1);
st.push(q);
}
}
}
}
//快速排序算法的改进:
/*改进1:如果数组近乎有序,标定点的选择会影响快速排序的性能,
如果每次都选择最小值作为标定点,快速排序时间复杂度会退化为O(n^{2}),因此需要随机化标定点元素。*/
template<class T>
void QuickSort_Fix1(T arr[], int begin, int end){
// 随机在arr[begin...end]的范围中, 选择一个数值作为标定点
swap(arr[begin], arr[rand() % (end - begin) + begin]);
//swap函数,把枢轴位置的元素和low位置元素互换,此时可以和普通的快排一样调用划分函数
if (begin < end){
T temp = arr[begin];
int i = begin;
int j = end;
while (i < j){
//当右边的数大于基准数时,略过,继续向左查找
//不满足条件时跳出循环,此时的j对应的元素是小于基准元素的
while (i < j&&arr[j] >temp)
{
j--;
}
arr[i] = arr[j];
//当左边的数小于等于基准数时,略过,继续向右查找
//(重复的基准元素集合到左区间)
//不满足条件时跳出循环,此时的i对应的元素是大于等于基准元素的
while (i < j&&arr[i] <= temp)
{
i++;
}
arr[j] = arr[i];
}
//此时i==j
arr[i] = temp;
QuickSort1(arr, begin, i - 1);
QuickSort1(arr, i + 1, end);
}
else
return;
}
//快速排序改进,选取合理的分割点
/*改进2:
找枢轴,将起始位置和中间位置
以及最后位置的值进行比较取中间值
*/
template<class T>
int GetMiddleValue(T arr[], int begin, int end)
{
int mid = (begin + (end - begin) / 2);
int y1 = arr[begin] > arr[mid] ? begin : mid;
int y2 = arr[begin] > arr[end] ? begin : end;
int y3 = arr[mid] > arr[end] ? mid : end;
if (y1 == y2)
{
return y3;
}
else
{
return arr[y1] > arr[y2] ? y2 : y1;
}
}
template<class T>
void QuickSort_Fix2(T arr[], int begin, int end){
// 随机在arr[begin...end]的范围中, 选择一个数值作为标定点
if (begin < end){
int mid = GetMiddleValue(arr, begin, end);
//将枢轴元素放在第一个位置
if (mid != begin)
{
T temp = arr[mid];
arr[mid] = arr[begin];
arr[begin] = temp;
}
T temp = arr[begin];
int i = begin;
int j = end;
while (i < j){
//当右边的数大于基准数时,略过,继续向左查找
//不满足条件时跳出循环,此时的j对应的元素是小于基准元素的
while (i < j&&arr[j] >temp)
{
j--;
}
arr[i] = arr[j];
//当左边的数小于等于基准数时,略过,继续向右查找
//(重复的基准元素集合到左区间)
//不满足条件时跳出循环,此时的i对应的元素是大于等于基准元素的
while (i < j&&arr[i] <= temp)
{
i++;
}
arr[j] = arr[i];
}
//此时i==j
arr[i] = temp;
QuickSort_Fix2(arr, begin, i - 1);
QuickSort_Fix2(arr, i + 1, end);
}
else
return;
}
template<class T>
void print(T arr[], int Length){
for (int i = 0; i <Length; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr3[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
int arr4[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
int arr5[8] = { 1, 4, 6, 9, 9, 10, 12, 2 };
int arr6[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
int length;
//表示用arr占用内存大小除以一个int型占用大小
length = sizeof(arr3) / sizeof(int);
cout << "测试数据为:" << endl;
print<int>(arr3, length);
cout << "使用快速排序(递归算法):" << endl;
QuickSort1<int>(arr3, 0, length - 1);
print<int>(arr3, length);
cout << "重新测试:" << endl;
print<int>(arr4, length);
cout << "使用快速排序(非递归算法(栈)):" << endl;
QuickSort2<int>(arr4, 0, length - 1);
print<int>(arr4, length);
cout << "重新测试:" << endl;
print<int>(arr5, length);
cout << "使用快速排序(改进(当数组近乎有序时)):" << endl;
QuickSort_Fix1<int>(arr5, 0, length - 1);
print<int>(arr5, length);
cout << "重新测试:" << endl;
print<int>(arr6, length);
cout << "使用快速排序(改进(三个数取中)):" << endl;
QuickSort_Fix2<int>(arr6, 0, length - 1);
print<int>(arr6, length);
system("pause"); //等待按任意键退出
return 0;
}
结果图: