[数据结构与算法]4种算法设计与改进(冒泡排序,快速排序(递归、非递归、近乎有序时改进、三点取中间值),插入排序、希尔排序)

#include "iostream"
#include<stack>
using namespace std;

//内部使用冒泡排序,进行希尔排序
template<class T>
void ShellBubbleSort(T a[], int Length){
	for (int gap = Length / 2; gap > 0; gap/=2){
		for (int i = 0; i < Length - 1; i += gap){
			for (int j = 0; j < Length - i - gap; j += gap){
				if (a[j]>a[j + gap]){
					T tmp = a[j + gap];
					a[j + gap] = a[j];
					a[j] = tmp;
				}
			}
			
		}
	}
}

//使用插入排序进行内部排序,测试
template<class T>
void test(T arr[], int Length){
	//先写出插入排序算法,再将其改为希尔排序,将所有1的地方改为gap
	for (int i = 1; i < Length; i++)
	{
		T val = arr[i];//记录值
		int j = i;//记录下标
		while (j>0 && arr[j - 1] > val&&j - 1 >= 0)//j等于0表示已经在最左边,不能移动了
		{
			arr[j] = arr[j - 1];//将左边的值往右边移一位					
			j = j - 1;//下标发生变化,位置左移一位
		}
		arr[j] = val;
		//cout << arr[j]<<endl;
		//cout << "gap"<<gap<<endl;
	}
}

//冒泡排序,外层遍历n-1次,内层每次对n-i-1个数进行比较
	template<class T>
	void BubbleSort(T arr[],int Length){
		for (int i = 0; i < Length - 1; i++)
		{
			for (int j = 0; j < Length - i - 1; j++)
			{
				if (arr[j]>arr[j + 1])
				{
					T temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
		
	}
	template<class T>
	void print(T arr[], int Length){
		for (int i = 0; i <Length; i++)
		{
			cout << arr[i] << " ";
		}
		cout << endl;
	}

//使用希尔排序
	template<class T>
	void ShellSort(T arr[], int Length)
	{
		for (int gap = Length / 2; gap > 0; gap /= 2){
			//先写出插入排序算法,再将其改为希尔排序,将所有1的地方改为gap
			for (int i = gap; i < Length; i++)
			{
				T val = arr[i];//记录值
				int j = i;//记录下标
				while (j>0 && arr[j-gap] > val&&j-gap>=0)//j等于0表示已经在最左边,不能移动了
				{				
					arr[j] = arr[j - gap];//将左边的值往右边移一位					
					j = j - gap;//下标发生变化,位置左移一位
				}
				arr[j] = val;
				//cout << arr[j]<<endl;
				//cout << "gap"<<gap<<endl;
			}
			
		}
	}


	//快速排序
	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;

	}



int main()
{
	
	int arr[8] = { 9, 4, 6, 2,9,5,4,1};
	int arr1[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
	int arr2[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
	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 arr7[8] = { 9, 4, 6, 2, 9, 5, 4, 1 };
	int length; 
	//表示用arr占用内存大小除以一个int型占用大小
	length = sizeof(arr) / sizeof(int);//所有测试数组都一样长
	
	cout << "测试数据为:" << endl;
	print<int>(arr, length);
	cout << "使用冒泡排序:" << endl;
	BubbleSort<int >(arr, length);
	print<int>(arr, length);

	cout << "重新测试:" << endl;
	print<int>(arr1, length);
	cout << "使用希尔排序(内部为冒泡排序):" << endl;
	ShellBubbleSort<int>(arr1, length);
	print<int>(arr1, length);
	
	cout << "重新测试:" << endl;
	print<int>(arr2, length);
	cout << "使用希尔排序(内部为插入排序):" << endl;
	ShellSort<int>(arr2, length);
	print<int>(arr2, length);
	
	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);
	
	cout << "重新测试:" << endl;
	print<int>(arr7, length);
	cout << "使用插入排序:" << endl;
	test<int>(arr7,length);
	print<int>(arr7, length);

	system("pause");				//等待按任意键退出
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值