插入排序:
对于少量的元素的排序,插入排序是一个很有效的算法。其原理很简单,类似于我们打扑克的时候,开始时,我们左手为空并且桌上的牌面向下,然后,我们每次从桌子上拿走一张牌并将它插入左手的正确位置,为了找到正确位置,我们从右往左将它与每张牌进行比较。
对于数组来说,我们就是从第二个元素开始,在该元素左边建立一个排好序的子数组,然后对右边的元素进行依次遍历,将它们插入到左边的子数组中,这样就排好序啦。
void inter_sort(int *a,int n)
{
for(int i=1;i<n;i++)
{
int temp=a[i];
j=i-1;
while(j>=0&&a[j]>temp)
{
a[j+1]=a[j];
j--
}
a[j+1]=temp;
}
}
归并排序
归并排序遵循的是分治法的思想:将原来的问题分解成几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解,来建立原问题的解。
如下图所示:
所以我们只需要一个解的合并函数,然后再有一个对原问题的分解的递归函数就可以解决问题啦。
void merge(int *a,int start,int mid,int end)
{
int i,j,k,n1,n2;
n1=mid-start+1;
n2=end-mid;
int *l=new int[n1];
int *r=new int[n2];
i=j=0;
while(i<n1)
l[i++]=a[start+i];
while(j<n2)
r[j++]=a[mid+j+1];
i=j=0;
k=start;
while(i<n1&&j<n2)
{
if(l[i]<r[j])
a[k++]=l[i++];
else
a[k++]=r[j++];
}
while(i<n1) a[k++]=l[i++];
while(j<n2) a[k++]=r[j++];
}
void merge_sort(int *a,int start,int end)
{
int mid;
if(start<end)
{
mid=(start+end)/2;
merge_sort(a,start,mid);
merge_sort(a,mid+1,end);
merge(a,start,mid,end);
}
}
我们可以总结一下两种排序的优缺点,它们都属于比较排序,所以它们的时间下界都是nlgn,插入排序的时间复杂度是O(n^2),归并排序的时间复杂度是O(nlgn),可以说归并排序的时间复杂度已经到了比较排序的下界,但是它用了O(n)的空间复杂度,而插入排序的空间复杂度只有O(1)。
那有没有时间复杂度和空间复杂度都很小的比较排序算法呢?我们下一篇堆排序和快排将会进行介绍。