快速排序和归并排序——两种较快的排序

题目:luogu1177.

题目大意:给一串序列从小到大排序,所以以下介绍的均默认为从小到大排序的.

快速排序的时间复杂度是平均O(nlog(n))的,不过还是可能变成O(n^2).

快速排序的具体思路就是,首先取一个中点mid,然后O(n)枚举一遍,使得序列变成比a[mid]大的数在mid右边,小的数在mid左边.

之后再次以mid为分界点,往下递归(l,mid-1)和(mid+1,r),重复上述过程.

那么这个算法平均时间复杂度就是O(nlog(n))的.

但是当这个中点mid的值a[mid]恰好是很大或者很小的,这个算法就会被卡到懵逼.

但通常情况下这个算法比一般的排序算法都快,因为常数小...

所以代码如下:

void qsort(int L,int R){
  int i=L,j=R,mid=a[L+R>>1];
  while (i<=j){
    while (a[i]<mid) i++;
    while (a[j]>mid) j--;
    if (i<=j) swap(a[i],a[j]),i++,j--;
  }
  if (L<j) qsort(L,j);
  if (i<R) qsort(i,R);
}

而归并排序的主要思想也是分治,只不过与快排不同的是,快排是先处理完再递归,而归并排序则是先递归完再处理.

这样我们可以不断地分到只剩一个元素,返回回来我们可以知道[l,mid]以及[mid+1,r]这两段一定是有序的,所以我们就可以合并这两段,时间复杂度O(n).

我们现在来计算复杂度,首先我们知道总共有log(n)层,接下来有每层肯定都是n个元素,所以时间复杂度为O(nlog(n)).

注意,归并排序的O(nlog(n))是稳定O(nlog(n)),而快排只是平均O(nlog(n)).

但是大多数情况下,归并排序比快速排序慢.

但归并排序的合并思想很不错,这种思想有时还会应用到一些题上,如瑞士轮一题.

归并排序代码如下:

void mergesort(int L,int R){
  if (L==R) return;
  int mid=L+R>>1;
  mergesort(L,mid);
  mergesort(mid+1,R);
  int i=L,j=mid+1,k=L;
  while (i<=mid&&j<=R)
    if (a[i]<a[j]) r[k++]=a[i++];
    else r[k++]=a[j++];
  while (i<=mid) r[k++]=a[i++];
  while (j<=R) r[k++]=a[j++];
  for (i=L;i<=R;i++)
    a[i]=r[i];
}

当然你在考试的时候手写排序是不存在的,排序直接写sort.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80665723
今日推荐