[C++]练习:使用模版进行快速排序,并改进(递归、非递归、近乎有序时、三个数取中值)

对上一篇博客进行拆分,修改

#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;
}

结果图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值