之前我的博客有排序算法总结
1、快速排序
快速排序的中心是填坑法,取一个数(这里选取第一个数)作为基准数temp,从队尾开始寻找第一个比基准数小的数a[j],交换a[j]和temp,然后队首开始查找第一个比temp大的数a[i],交换之,遍历的结果是当i>=j时,temp左边的数都小于temp,后边的数都大于temp,这个有点像归并排序。最后利用递归调用完成排序,代码如下:
void QuickSort(int a[], int l,int r){
if(l<r){
int i=l,j=r,temp=a[l];
while(i<j){
while(i<j&&temp<=a[j])
--j;
if(i<j)
a[i++]=a[j];
while(i<j&&temp>a[i])
++i;
if(i<j)
a[j--]=a[i];
}
a[i]=temp;
QuickSort(a,l,i-1);
QuickSort(a,i+1,r);
}
}
在笔试题中很多人选择快速排序作为基础算法对数组进行排序,一般认为快速排序是内部排序中最好的排序法之一,其平均时间复杂度为O(nlogn),但在已经完成排序的情况下,其最坏复杂度可以为O(n^2),且不稳定。
2、堆排序
堆排序是基于完全二叉树的排序方法,其中心思想是首先构造最大堆(或最小堆),即父节点总是大于其子节点,然后将堆化的数组a[0]与a[i]交换,即将最大数置于i位置,再将0—i的继续堆化,重新选出最大的数于a[0],完成第一个排序。经过遍历完成排序,其代码为:
//构造最大堆
void MaxHeapFixDown(int a[], int i, int n){
int j = 2*i+1;
int temp = a[i];
while(j<n){
if(j+1<n&&a[j]<a[j+1])
++j;
if(temp>a[j])
break;
else{
a[i]=a[j];
i=j;
j=2*i+1;
}
}
a[i]=temp;
}
//堆排序
void HeapSort(int a[], int n){
for(int i= n/2-1;i>=0;i--)
MaxHeapFixDown(a,i,n);
for(int i=n-1;i>=1;i--){
swap(a[i],a[0]);
MaxHeapFixDown(a,0,i);
}
}
堆排序相对快速排序最大的有点时即便在最坏的情况下其复杂度也能达到O(nlogn),但也是不稳定排序.
3、基数排序
基数排序中心思想是基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。
//寻找数组中最大数的位数作为基数排序循环次数
int KeySize(int a[], int n){
int key = 1;
for(int i=0;i<n;i++){
int temp = 1;
int r = 10;
while(a[i]/r>0){
temp++;
r*=10;
}
key = (temp>key)?temp:key;
}
return key;
}
//基数排序
void RadixSort(int a[], int n){
int key = KeySize(a,n);
int bucket[10][10]={0};
int order[10]={0};
for(int r = 1;key>0;key--,r*=10){
for(int i=0;i<n;i++){
int lsd = (a[i]/r)%10;
bucket[lsd][order[lsd]++]=a[i];
}
int k = 0;
for(int i = 0;i<10;i++){
if(order[i]!=0){
for(int j = 0;j<order[i];j++)
a[k++]=bucket[i][j];
}
order[i]=0;
}
}
}
基数排序是稳定算法,效率很高,其复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数。但它只能用在整数的排序中,且需要借助一定的辅助空间。