一些函数准备:数组元素交换函数、数组打印函数、获取数组长度函数。
#include<iostream>
#include<ctime>
using namespace std;
void exchange(int *list,int i,int j)
{
int temp=0;
temp=list[i];
list[i]=list[j];
list[j]=temp;
}
template <class T>
int length(T& list)
{
int len=(int)sizeof(list)/sizeof(list[0]);//使用sizeof,不能传递指针
return len;
}
void print(int *list,int len)
{
for(int i=0;i<=len-1;i++)
{
cout<<list[i]<<" ";
}
cout<<endl;
}
交换类排序(冒泡、快排)
冒泡(经典):两两比较相邻记录,如果反序则交换,直到整个序列没有反序;
void bubble_sort(int *list,int len)
{
int i,j;
for(i=1;i<=len-1;i++)
for(j=0;j<len-i;j++)
{
if(list[j]>list[j+1])
{
exchange(list,j,j+1);
}
}
}
第i轮,倒数第i个位置上得到正确的元素。
冒泡(改进):立一个flag,监控是否有元素交换,若有,则继续循环,否则退出循环;
//改进的冒泡排序
void bubble_sort2(int *list,int len)
{
int flag=true;
int i=1,j=0;
while((i<=len-1) && flag)
{
flag=false;
for(j=0;j<len-i;j++)
{
if(list[j]>list[j+1])
{
exchange(list,j,j+1);
flag=true;
}
}
i++;
}
}
快排(重要):首先确定一个枢纽值,通过一趟快排将元素分割为两个部分,左边部分的元素都比枢纽值小,右边部分的值都比枢纽值大。实现的关键就是用两个指针low,high;low从左往右寻找比枢纽大的值,交换到枢纽右边;high从右往左寻找比枢纽小的值,交换到枢纽左边。当low==high时,说明找到了枢纽值的正确位置,将枢纽值与low位置处的值交换。然后再将分割的两个部分分别递归调用该方法,直到整个序列有序。参考:https://blog.csdn.net/adusts/article/details/80882649
void quick_sort(int *list, int left, int right)
{
int i,j,temp;
temp=list[left];
i=left; j=right;
if(left>right)
return;
while(i!=j)
{
while(list[j]>=temp && j>i)
j--;
while(list[i]<=temp && i<j)
i++;
if(i<j)
{
exchange(list,i,j);
}
}
list[left]=list[i];
list[i]=temp;
print(list,right+1);
quick_sort(list,left,i-1);
quick_sort(list,i+1,right);
}
选择类排序(简单选择排序、堆排序)
简单选择排序:对于当前的位置i,经过n-i次比较,从n-i+1个数据中选出最小关键字,并与i位置的值进行交换;选择排序能够保证位置i前面的数据是顺序排列的。
void select_sort(int *list,int len)
{
int i,j,min;
for(i=0;i<len-1;i++)
{ min=i;
for(j=i+1;j<len;j++)
if(list[j]<list[min])
{
min=j;
}
exchange(list,i,min);
}
}
堆排序:堆是一种完全二叉树,有大顶堆和小顶堆。大顶堆的所有节点元素都比其左右孩子节点元素值大,小顶堆反之。将序列构成一个大顶堆,然后将堆顶元素与叶子节点元素交换,此时将剩余的n-1个元素重新构造成一个堆,反复执行就可以得到一个有序序列;参考:https://www.cnblogs.com/wanglei5205/p/8733524.html
//大顶堆调整
void heap_adjust(int *list,int len,int index)
{
int left = 2*index+1;
int right = 2*index+2;
int maxIdx = index;
if(left<len && list[left]>list[maxIdx]) maxIdx = left;
if(right<len && list[right]>list[maxIdx]) maxIdx = right;
if(maxIdx != index)
{
exchange(list,maxIdx,index);
print(list,len);
cout<<maxIdx<<" "<<index<<endl;
heap_adjust(list,len,maxIdx);
}
}
//交换元素并进行堆调整
void heap_sort(int *list,int len)
{
for(int i=len/2-1;i>=0;i--) //最后一个非叶子节点的下标为len/2-1
{
heap_adjust(list,len,i);
}
for(i=len-1;i>=1;i--)
{
exchange(list,0,i);
heap_adjust(list,i,0);
}
}
插入类排序(直接插入排序、shell排序)
直接插入排序:将一个待排元素插入到它前面已经排好的序列当中,依次比较它与前面的元素,若比待排元素大,就将这个元素后移,直到找到一个合适的位置将待排元素插入序列。(类似于扑克牌)
void insert_sort(int *list,int len)
{
int i,j,temp;
for(i=1;i<=len-1;i++)
{
temp=list[i];
for(j=i-1;j>=0;j--)
{
if(list[j]>temp)
list[j+1]=list[j];
else
{
break;
}
}
list[j+1]=temp;
}
}
shell排序:也叫增量减小排序,在直接插入排序基础上增加了“增量”。设置一个增量,根据增量将整个待排序列分割成为若干子序列,对每一个子序列分别进行直接插入排序。当增量减小为1时,对全体记录进行一次直接插入排序。时间节省在:对子序列排序,因为子序列元素少,所以排序快;最后一轮对所有数据排序,但此时大部分数据已经有序,所以可以节省很多时间。
void shell_sort(int *list,int len)
{
int inc=len;
int temp=0;
int j;
do{
inc = inc/3+1;
for (int i=inc;i<len;i++)
{
temp=list[i];
for(j=i-inc;j>=0;j-=inc)
{
if(list[j]>list[i])
list[j+inc]=list[j];
else
break;
}
list[j+inc]=temp;
}
}while(inc>1);
}
归并排序
归并排序:分治法排序。先将n个记录看成是n个有序子序列,每个序列中只有1个元素,然后两两归并,得到n/2个有序子序列,然后再两两归并,直到得到一个长度为n的子序列。归并排序每次都是将有序子序列合并在一起。
参考:https://www.cnblogs.com/WuNaiHuaLuo/p/5446449.html
https://www.cnblogs.com/eudiwffe/p/6254394.html
//归并排序
void merge_core(int *list,int begin, int mid, int end)
{
int i=begin,j=mid,k=0;
int *tmp = (int*)malloc(sizeof(int)*(end-begin));
for(;i<mid && j<end; )
tmp[k++]=(list[i]<list[j]?list[i++]:list[j++]);
for(;i<mid;)
tmp[k++]=list[i++];
for(;j<end;)
tmp[k++]=list[j++];
for(i=begin,k=0;i<end;)
list[i++]=tmp[k++];
free(tmp);
}
void merge_sort(int *list,int begin,int end)
{
if(end-begin < 2) return;
int mid = (begin+end)>>1;
merge_sort(list,begin,mid);
merge_sort(list,mid,end);
merge_core(list,begin, mid, end);
}
main函数:
int main()
{
time_t c_start,c_end;
int arr[] = {7,33,5,22,8,9};
//int arr[] = {0,1,2,3,4,5,6,7};
int len=length(arr);
int choose;
cout<<"************original arr******************"<<endl;
print(arr,len);
cout<<"input the operation"<<endl;
cin>>choose;
switch(choose)
{
case 1:
c_start=clock();
bubble_sort(arr,len);
c_end=clock();
cout<<"************bubble_sort******************"<<endl;
print(arr,len);
cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
break;
case 2:
c_start=clock();
bubble_sort2(arr,len);
c_end=clock();
cout<<"************bubble_sort2******************"<<endl;
print(arr,len);
cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
break;
case 3:
c_start=clock();
select_sort(arr,len);
c_end=clock();
cout<<"************select_sort******************"<<endl;
print(arr,len);
cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
break;
case 4:
c_start=clock();
insert_sort(arr,len);
c_end=clock();
cout<<"************insert_sort******************"<<endl;
print(arr,len);
cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
break;
case 5:
c_start=clock();
shell_sort(arr,len);
c_end=clock();
cout<<"************shell_sort******************"<<endl;
print(arr,len);
cout<<"time cost: "<<difftime(c_end,c_start)<<"ms"<<endl;
break;
case 6:
heap_sort(arr,len);
cout<<"************heap_sort******************"<<endl;
print(arr,len);
case 7:
quick_sort(arr,0,len-1);
cout<<"************quick_sort******************"<<endl;
print(arr,len);
case 8:
merge_sort(arr,0,len);
cout<<"************merge_sort******************"<<endl;
print(arr,len);
}
return 0;
}
各种排序时间/空间复杂度分析: