#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;
}
[数据结构与算法]4种算法设计与改进(冒泡排序,快速排序(递归、非递归、近乎有序时改进、三点取中间值),插入排序、希尔排序)
最新推荐文章于 2022-01-06 23:32:37 发布