归并排序
归并排序体现了分治思想,时间复杂度是O(nlogn),空间复杂度是O(n)。
归并排序是将序列不断二分,最终分成单个元素,再两两合并,最终达到整个序列有序。
1 void msort(int l,int r) { 2 if(l==r) return; //划分到单个元素就返回 3 int m=l+(r-l)/2,p=l,q=m+1,k=l; 4 msort(l,m); //划分左右序列 5 msort(m+1,r); 6 while(p<=m||q<=r) //将左右序列合并成有序序列 7 if(q>r||(a[p]<a[q]&&p<=m)) T[k++]=a[p++]; 8 else T[k++]=a[q++]; 9 for(k=l;k<=r;++k) a[k]=T[k]; //将合并后的序列放到原序列中 10 }
归并排序的效率很高,而且不像快排那样会被特殊数据卡掉,只不过需要辅助内存。归并排序还有一种用途,就是统计逆序对。逆序对是指在一个序列中位置与值不对应的数对,如:1 3 2 4 7,就有(3,2),(3,4),(3,7)这三对逆序对。朴素的算法需要两层循环,复杂度是O(n^2)的,而归并排序本身的特性却可以让我们方便地统计逆序对。由于合并左右两个序列时,两个序列已有序,因此当出现右边元素大于左边元素时,此时左边序列剩余元素个数就是逆序对个数的一部分。
1 void msort(int l,int r) { 2 if(l==r) return; //划分到单个元素就返回 3 int m=l+(r-l)/2,p=l,q=m+1,k=l; 4 msort(l,m); //划分左右序列 5 msort(m+1,r); 6 while(p<=m||q<=r) //将左右序列合并成有序序列 7 if(q>r||(a[p]<a[q]&&p<=m)) T[k++]=a[p++]; 8 else T[k++]=a[q++],cnt+=m-p+1; //顺便统计逆序对个数 9 for(k=l;k<=r;++k) a[k]=T[k]; //将合并后的序列放到原序列中 10 }