插入排序: j位置的数插入到前面哪一个位置 冒泡排序:每一次遍历找出最大的数
for(int i=1;i<n;i++) for(int i=0;i<n-1;i++)
for(int j=i;j>0;j--) //前面为已经排好的数 for(int j=0;j<n-1-i;j++) //后面为已经排好的数
{ {
if(a[j]<a[j-1]) if(a[j]>a[j+1]
swap(a[j],s[j-1]); swap(a[j],a[j+1];
} }
快速排序:从数列中选取一个数作为基准,小于它的放左边,大于它的放右边 选择排序:每一次选取最小的数放右
void quicksort(int *a,int n,int l,int r) void selectsort(int *a,int n)
{ {
if(l<r) for(int i=0;i<n-1;i++)
{ {
int i=l,j=r,x=a[l]; int min=i;
while(i<j) for(int j=i+1;j<n;j++)
{ if(a[min]>a[j])
while(i<j&&a[j]>=x) j--; min=j;
if(i<j) a[i++]=a[j]; swap(a[min],a[i]);
while(i<j&&a[i]<x) i++; }
if(i<j) a[j--]=a[i];
}
a[i]=x;
quicksort(a,n,l,i-1);
quicksort(a,n,i+1,r);
}
}
堆排序:
void m(int *a,int i,int low,int high) //对堆内的元素调整
{
int l=2*i+1,r=2*i+2,largest=i;
if(l<=high&&a[l]>a[i])
largest=l;
if(r<=high&&a[r]>a[largest]) //对i节点,如果孩子节点比父节点大,取最大的孩子节点,交换孩子和父节点
largest=r;
if(largest!=i)
{
swap(a[largest],a[i]);
m(a,largest,low,high);
}
}
void create(int *a,int n) //建堆
{
for(int i=n/2-1;i>=0;i--)
m(a,i,0,n-1);
}
void dsort(int *a,int n)
{
create(a,n);
for(int i=n-1;i>0;i--)
{
swap(a[0],a[i]);
m(a,i,0,n-1);
}
}
归并排序
void m(int *a,int p,int q,int r)
{
int t1=q-p+1;
int t2=r-q;
int *l=new int[t1];
int *r=new int[t2];
for(int i=0;i<t1;i++)
l[i]=a[p+i];
for(int i=0;i<t2;i++)
r[i]=a[q+i+1]; //划分成两个数组
for(int i=0,j=0,k=p;k<r;k++)
{
if(l[i]<r[j])
{
a[k]=l[i]; //有序合并两个数组
i++;
}
else
{
a[k]=r[j];
j++;
}
}
}
void gsort(int *a,int p,int r)
{
if(p<r)
{
int q=(p+r)/2;
gsort(a,p,q);
gsort(a,q+1,r);
m(a,p,q,r);
}
}
排序比较
排序 平均 最好 最差 稳定 备注
插入 n2 n n2 稳定 大部分已排序好
选择 n2 n2 n2 不稳定 小数目
冒泡 n2 n n2 稳定 小数
快速 nlogn nlogn n2 不 n大
归并 nlogn nlogn nlogn 稳定 n大 维护一个数组
堆 nlogn nlogn nlogn 不稳定 n大
稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变
堆排:适用于大数据(百万级),因为快排和归并排序都是基于递归的,大数据容易栈溢出。
stl中的sort函数实现
sort并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序