c++STL里面是有排序接口的,不过还是想学习一下经典的排序算法。我没有使用模板类来实现,而是指定了整形数组。
上代码,方便以后看:
***.h
#pragma once
#include <iostream>
#include <vector>
using namespace std;
class MySort
{
public:
MySort();
~MySort();
/*初级排序*/
void SelectSort(vector<int> &a);
void InsertSort(vector<int> &a);
/*改进初级排序*/
void ShellQuickSort(vector<int>& a);
void ShellQuickSort(vector<int>& a,bool (*P_less)(int &x,int &y));
/*归并排序-渐进最优(最坏情况与最好情况下的时间复杂度一致)*/
void MergeQuickSort(vector<int>& a);
void MergeQuickSort(vector<int>& a,int low,int high);
/*快速排序*/
/*基本快排*/
void QuickSort(vector<int>& a);
void QuickSort(vector<int>&a,int low,int high);
/*改进快排*/
private:
void exchan(vector<int> &a, int j, int k);
bool less(int &x,int &y);
void merge(vector<int> &a, int low, int mid, int high);
int partition(vector<int> &a,int low, int high);
vector<int> aux;
};
***.cpp
#include "MySort.h"
MySort::MySort()
{
}
MySort::~MySort()
{
}
/*======================选择排序==========================
选择排序:
选择最小的放在左端
原地排序算法;基本排序算法;
*/
void MySort::SelectSort(vector<int>& a)
{
int N = a.size();
int tmp;
int min;
for (int i = 0; i < N; i++) {
min = i;
for (int j = i + 1; j < N; j++) {
if (less(a[j], a[i]))
min = j;
}
exchan(a, i, min);
}
}
/*========================插入排序==========================
插入排序:
遍历到某一位元素,就将该元素左侧排序
原地排序算法;基本排序算法;
*/
void MySort::InsertSort(vector<int>& a)
{
int N = a.size();
for (int i = 0; i < N-1;i++) {
for (int j = i + 1; j >= 0;j--) {
if (less(a[j], a[j - 1]))
exchan(a,j,j-1);
}
}
}
/*===========================希尔排序shell-sort=========================
改进了插入排序:
插入排序适合小规模和部分有序的数据进行排序,
希尔排序再进行h=1的排序之前的操作就是将原始数据进行部分排序;
原地排序算法;改进的基本排序算法;
时间复杂度:不确定
*/
void MySort::ShellQuickSort(vector<int>& a)
{
int N = a.size();
int h = 1;
while (h < N / 3)
h = 3 * h + 1;//1,4,13,40,121,364……h的初始值。例如h=13,那么第一次做13-有序,4-有序,1-有序
while (h >= 1) {
//将数组变为h有序
for (int i = h; i < N; i++) {
for (int j = i; j >= h && less(a[j], a[j - h]); j -= h) {
exchan(a,j,j-h);
}
}
h = h / 3;
}
}
/*重载一个可以自定义比较方法的希尔排序*/
void MySort::ShellQuickSort(vector<int>& a, bool(*P_less)(int &x, int &y))
{
int N = a.size();
int h = 1;
while (h < N / 3)
h = 3 * h + 1;
while (h >= 1) {
//将数组变为h有序
for (int i = h; i < N; i++) {
for (int j = i; j >= h && (*P_less)(a[j], a[j - h]); j -= h) {
exchan(a, j, j - h);
}
}
h = h / 3;
}
}
/*=================================归并排序================================
归并排序:拆分原序列,对两条子序列先排序后归并;子序列排序:递归调用
此处实现了自顶向下的归并排序,因为使用递归,应该不适合超长序列,以免爆栈
原地归并排序,额外空间为常数;
时间复杂度:~Nlog(N),渐进最优的基于比较的排序算法
空间复杂度:不是最优
*/
void MySort::MergeQuickSort(vector<int>& a)
{
aux.assign(a.begin(),a.end());
MergeQuickSort(a,0,a.size()-1);
}
void MySort::MergeQuickSort(vector<int>& a, int low, int high)
{
if (high <= low) return;
int mid = low + (high - low) / 2;
MergeQuickSort(a, low, mid);
MergeQuickSort(a, mid + 1, high);
merge(a,low,mid,high);
}
/*=================================快速排序=================================
快速排序:寻找切分点,切分点是归位元素,递归寻找子序列切分点
快速排序是一个自底向上的排序,迭代最外层是有序的起点,这与归并排序是相反的
时间复杂度优于归并排序和插入排序
归并排序和快速排序都体现了分治的思想,并且递归过程十分相似
*/
void MySort::QuickSort(vector<int>& a)
{
//打乱顺序省略
QuickSort(a,0,a.size()-1);
}
void MySort::QuickSort(vector<int>& a, int low, int high)
{
if (low >= high) return;
int j = partition(a,low,high);//寻找并归位切分点
QuickSort(a,low,j-1);
QuickSort(a,j+1,high);
}
/*======================================PRIVATE===================================*/
void MySort::exchan(vector<int> &a, int j, int k)
{
int tmp;
tmp = a[j];
a[j] = a[k];
a[k] = tmp;
}
bool MySort::less(int &x, int &y)
{
if (x <= y)
return true;
return false;
}
/*===========================归并算法===============================
归并算法:
本工程中专门为归并排序调用,设为私有成员;
合并原序列的两条有序子序列;
原地归并;
*/
void MySort::merge(vector<int>& a, int low, int mid, int high)
{
int i = low;
int j = mid + 1;
for (int k = low; k <= high; k++) {
aux[k] = a[k];
}
for (int k = low; k <= high;k++) {
if (i > mid)
a[k] = aux[j++];
else if (j > high)
a[k] = aux[i++];
else if (less(aux[i], aux[j]))
a[k] = aux[i++];
else
a[k] = aux[j++];
}
}
/*=========================切分算法=================================
切分算法:
切分的过程就是随即确定一个切分点,然后移动左右哨兵
使得左哨兵不大于切分点,右哨兵不小于切分点
如果先移动的是左哨兵,那么左右哨兵碰撞的时候一定是右哨兵碰撞左哨兵,此时
需要交换切分值与右哨兵的元素,完成切分值归位,并返回右哨兵
*/
int MySort::partition(vector<int>& a, int low, int high)
{
int i = low;
int j = high + 1;
int val = a[low];
while (1) {
while (less(a[++i], val))
if (i == high)
break;
while (less(val, a[--j]))
if (j == low)
break;
if (i >= j)
break;
exchan(a,i,j);
}
exchan(a,low,j);
return j;
}
测试结果:
使用50000个随机数,慢的排序会导致应用线程直接退出,所以先比较速度比较快地三个排序:希尔排序、归并排序、快速排序
#if SORT_TEST
MySort sortAPI;
vector<int> v_0;
for (int i = 0; i < 50000; i++) {
v_0.push_back(rand());
}
vector<int> v_1 = v_0;
vector<int> v_2 = v_0;
vector<int> v_3 = v_0;
vector<int> v_4 = v_0;
DWORD start;
//start = GetTickCount();
//sortAPI.InsertSort(v_0);
//cout << (GetTickCount() - start) << endl;
//start = GetTickCount();
//sortAPI.SelectSort(v_1);
//cout << (GetTickCount() - start) << endl;
start = GetTickCount();
sortAPI.ShellQuickSort(v_0);
cout << (GetTickCount() - start) << endl;
start = GetTickCount();
sortAPI.MergeQuickSort(v_1);
cout << (GetTickCount() - start) << endl;
start = GetTickCount();
sortAPI.QuickSort(v_2);
cout << (GetTickCount() - start) << endl;
#endif
两个比较慢的排序:选择排序,插入排序,500个随机数
对于随机数的排序效率:插入排序<选择排序<希尔排序<归并排序<快速排序