本文对各个排序算法进行了一点复习整理,并通过一段代码对几种排序算法进行了实现。这包括:冒泡排序,插入排序,选择排序,希尔排序,堆排序,归并排序,快速排序,基数排序,计数排序等。相关简要讨论在程序中有一定说明。
各种算法实现见以下示例代码:
/*******************************************************************
*各种排序算法示例程序---By F8Master
*/
#include<stdlib.h>
#include<iostream>
#include<vector>
#include<iomanip>
using namespace std;
template <class Comparable>
void bubbleSort(vector<Comparable> &a);
template<typename Comparable>
void insertSort(vector<Comparable> &a);
template<typename Comparable>
void selectSort(vector<Comparable> &a);
template<typename Comparable>
void shellSort(vector<Comparable> &a);
template<typename Comparable>
void heapSort(vector<Comparable> &a);
template<typename Comparable>
void mergeSort(vector<Comparable> &a);
template<typename Comparable>
void quickSort(vector<Comparable> &a);
template<typename Comparable>
void countSort(vector<Comparable> &a);
template<typename Comparable>
void radixSort(vector<Comparable> &a);
void main()
{
vector<int> v;
while(true)
{
cout<<"Choose sort Algorithm(0 for end) :"<<endl;
int num=0;
cout<<setw(2)<<++num<<setw(20)<<"BubbleSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"InsertSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"SelectSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"ShellSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"HeapSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"MergeSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"QuickSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"CountSort"<<endl;
cout<<setw(2)<<++num<<setw(20)<<"RadixSort"<<endl;
int selnum;
cin>>selnum;
if(selnum==0)
break;
v.clear();
for(int i=0;i<128;i++)
v.push_back(rand()%1000);
cout<<"Before sort:"<<endl;
for(int i =0;i<v.size();i++)
cout<<setw(5)<<v[i];
cout<<endl;
switch(selnum)
{
case 1: bubbleSort(v);
case 2: insertSort(v);
case 3:selectSort(v);
case 4:shellSort(v);
case 5: heapSort(v);
case 6: mergeSort(v);
case 7: quickSort(v);
case 8: countSort(v);
case 9: radixSort(v);
default:break;
}
cout<<"\nAfter sort:"<<endl;
for(int i =0;i<v.size();i++)
cout<<setw(5)<<v[i];
cout<<endl;
}
system("pause");
}
/*****************************************************************/
/* 冒泡排序基本思想是:两两比较相邻记录的关键字,如果反序则交换
*时间复杂度最好的情况为O(n),最坏的情况是O(n^2);是一种稳定的排序算法
*/
template <class Comparable>
void bubbleSort(vector<Comparable> &a)//冒泡
{
for(int i = 1;i<a.size();i++)
{
for(int j = 0;j<a.size()-i;j++)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}
}
/**************************************************************************/
/**************************************************************************/
/*插入排序基本思想: 将一个记录插入到前面已经排好序的序列中, 从而得到一个新的,记录数增1的序列
* 时间复杂度也为O(n^2), 若列表基本有序,则插入排序比冒泡、选择更有效率 */
template<typename Comparable>
void insertSort(vector<Comparable> &a)//插入
{
insertSort(a,0,a.size()-1);
}
template<typename Comparable>
void insertSort(vector<Comparable> &a, int left, int right)//插入实现,将在快排中用到
{
for(int i = left+1;i<right-left+1;i++)
{
int tmp = a[i];
int j;
for(j=i-1;j>=i &&tmp<a[j];j--)
a[j+1]=a[j];
a[j+1]=tmp;
}
}
/**************************************************************************/
/**************************************************************************/
/* 选择排序基本思想:就是通过n-i次比较,从n-i+1个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换。
* 时间复杂度也为O(n^2),但选择排序的性能要略优于冒泡排序 */
template<typename Comparable>
void selectSort(vector<Comparable> &a)//选择
{
for(int i=0;i<a.size();i++)
{
int pos = i;
int min = a[i];
for(int j = i+1;j<a.size();j++)
{
if(a[j]<min)
{
min = a[j];
pos = j;
}
}
swap(a[i],a[pos]);
}
}
/**************************************************************************/
/*希尔排序基本思想:间隔一定增量的元素进行排序,一次见效增量值直到1
*效率估计O(nlog2^n)~O(n^1.5),取决于增量值的最初大小。建议使用质数作为增量值,本程序并未如此实现
/**************************************************************************/
template<typename Comparable>
void shellSort(vector<Comparable> &a)//希尔
{
for(int gap = a.size()/2;gap>0;gap/=2)
{
for(int i=gap;i<a.size();i++)
{
int tmp = a[i];
int j=i;
for( ; j>=gap&&tmp<a[j-gap];j-=gap)
a[j]=a[j-gap];
a[j]=tmp;
}
}
}
/**************************************************************************/
/**************************************************************************/
/*通过构造最大堆,并依次交换最大元素与末尾元素实现排序
*时间复杂度为 O(nlogn)
*/
template<typename Comparable>
void heapSort(vector<Comparable> &a)//堆排序
{
for(int i=a.size()/2;i>=0;i--)//构造最大堆
percDown(a,i,a.size());
for(int j = a.size()-1;j>0;j--)
{
swap(a[0],a[j]);
percDown(a,0,j);
}
}
int leftChild(int i)
{
return i*2+1;
}
template<typename Comparable>
void percDown(vector<Comparable> &a,int i,int n)
{
int child;
int tmp;//存较小的值
for(tmp = a[i];leftChild(i)<n;i=child)
{
child = leftChild(i);
if(child!=n-1 && a[child]<a[child+1])
child++;
if(tmp<a[child])
a[i]=a[child];
else
break;
}
a[i]=tmp;
}
/********************************************************************************/
/********************************************************************************/
/*通过递归实现,将已经有序的两个序列合并为一个序列,该方法对空间的要求较高
* 时间复杂度为O(nlogn),空间复杂度为O(n+logn)
*/
template<typename Comparable>
void mergeSort(vector<Comparable> &a)//归并排序
{
vector<Comparable> tmpArray(a.size());//临时存储数组
mergeSort(a,tmpArray,0,a.size()-1);
}
template<typename Comparable>
void mergeSort(vector<Comparable> &a, vector<Comparable> &tmpArray, int left, int right)//归并排序递归调用部分
{
if(left<right)
{
int center = (left + right)/2;
mergeSort(a,tmpArray,left,center);
mergeSort(a,tmpArray,center+1,right);
merge(a,tmpArray,left,center+1,right);
}
}
template<typename Comparable>
void merge(vector<Comparable> &a, vector<Comparable> &tmpArray, int leftPos, int rightPos, int rightEnd)//归并排序合并部分
{
int leftEnd = rightPos-1;
int tmpPos = leftPos;
int numElements= rightEnd - leftPos +1;
while(leftPos<=leftEnd && rightPos<=rightEnd)
{
if(a[leftPos]<a[rightPos])
tmpArray[tmpPos++]=a[leftPos++];
else
tmpArray[tmpPos++]=a[rightPos++];
}
while(leftPos<=leftEnd)
tmpArray[tmpPos++]=a[leftPos++];
while(rightPos<=rightEnd)
tmpArray[tmpPos++]=a[rightPos++];
for(int i=0;i<numElements;i++,rightEnd--)
a[rightEnd]=tmpArray[rightEnd];
}
/********************************************************************************/
/********************************************************************************/
/*快速排序基本思想:通过递归实现,选定一个枢纽元素,对待排序序列进行分割,
分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。
平均时间复杂度O(nlogn)
*/
template<typename Comparable>
void quickSort(vector<Comparable> &a)//快速排序
{
quickSort(a,0,a.size()-1);
}
template<typename Comparable>
void quickSort(vector<Comparable> &a,int left, int right)//快速排序实现
{
if(left+10<=right)
{
Comparable pivot = median3(a,left,right);//确定枢纽元
int i =left,j=right-1;
for( ; ; )
{
while(a[++i]<pivot){}//找到左边首个不小于pivot的值
while(a[--j]>pivot){}//找到右边首个不大于pivot的值
if(i<j)
swap(a[i],a[j]);
else
break;
}
swap(a[i],a[right-1]);
quickSort(a,left,i-1);
quickSort(a,i+1,right);
}
else
insertSort(a,left,right);
}
template<typename Comparable>
const Comparable &median3(vector<Comparable> &a,int left,int right)
{
int center = (left+right)/2;
if(a[left]>a[center])
swap(a[left],a[center]);
if(a[left]>a[right])
swap(a[left],a[right]);
if(a[center]>a[right])
swap(a[center],a[right]);//交换后大小顺序为左<中<右
swap(a[center],a[right-1]);//枢纽元放在a[right-1]位置
return a[right-1];
}
/********************************************************************************/
/********************************************************************************/
/*计数排序基本思想:通过一个额外的count数据记录出每个元素的个数,并计算出应该出现的位置,从而实现排序
*该方法不基于比较
*/
template<typename Comparable>
void countSort(vector<Comparable> &a)//计数排序
{
Comparable min,max;
findMinMax(a,a.size(),&min,&max);
int numElements = max-min+1; //跨度范围
vector<Comparable> count(numElements,int(0));
for(int i = 0;i<a.size();i++)//计数
{
count[a[i]-min]++;
}
for(int i=0,j=0;i<numElements;i++)//重写原数组
{
while(count[i]>0)
{
a[j++]=i+min;
--count[i];
}
}
}
template<typename Comparable>
void findMinMax(vector<Comparable> &a,int size,Comparable *min,Comparable *max)
{
if(size==0)
return;
else if(size==1)
{
*min = *max = a[0];
return;
}
else
{
*min = a[0]<a[1]?a[0]:a[1];
*max = a[0]>a[1]?a[0]:a[1];
Comparable tmpMin;
Comparable tmpMax;
int i,j;
for(i = 2,j = 3 ; i<size&&j<size ;i+=2,j+=2)
{
tmpMin = a[i]<a[j]?a[i]:a[j];
tmpMax = a[i]>a[j]?a[i]:a[j];
if(tmpMin<*min)
*min = tmpMin;
if(tmpMax>*max)
*max = tmpMax;
}
if(size%2!=0)
{
if(a[size -1] > *max)
*max = a[size - 1];
else if(a[size -1] < *min)
*min = a[size -1];
}
}
}
/********************************************************************************/
/********************************************************************************/
/*基数排序基本思想:对于int型而言,可以解释为一次一句百位、十位、个位进行分组,组内递归调用进行排序
*/
template<typename Comparable>
void radixSort(vector<Comparable> &a)//基数排序
{
radixSort(a,0,a.size()-1,3);
}
template<typename Comparable>
void radixSort(vector<Comparable> &a,int left,int right,int d)
{
int i,j,radix=10,p1,p2;
vector<Comparable> count(radix,int(0));//计数数组
vector<Comparable> auxArray(right-left+1);//辅助数组
if(d<=0)//递归截止条件
return;
for(i=left;i<=right;i++)
count[getDigit(a[i],d)]++;
for(j=1;j<radix;j++)
count[j]+=count[j-1];
for(i=left;i<=right;i++)
{
j=getDigit(a[i],d);
auxArray[count[j]-1]=a[i];
count[j]--;
}
for(i=left,j=0;i<=right;i++,j++)//辅助数组元素写入原数组
{
a[i]=auxArray[j];
}
for(j=0;j<radix;j++)
{
p1=count[j]+left;
if(j==radix-1)
p2=right;
else
p2=count[j+1]-1+left;
if(p1<p2)
radixSort(a,p1,p2,d-1);
}
}
int getDigit(int a,int d)//返回指定位的值,个位为d=1,以此类推
{
int tmp=1;
for(int i=0;i<d-1;i++)
tmp*=10;
return (a / tmp)%10;
}