算法导论笔记 第8章 线性时间排序

任何比较排序在最好状况下都要通过Ω(nlgn),即比较排序的下界为Ω(nlgn)。ios

合并排序和堆排序都是渐进最优的。算法

要突破Ω(nlgn),就要进行非比较排序。计数排序、基数排序和桶排序都有非比较的一些操做来肯定排序顺序,它们能够达到线性运行时间。数组

 

计数排序法:spa

计数排序的基本思想是对每个输入元素x,肯定出小于x的元素个数。有了这个信息就能够把x直接放到他在最终输出数组中的位置上。code

计数排序适用于小范围集合的排序。它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 可是当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序。orm

代码以下:blog

#include <iostream>
#include <limits.h>

//输入 A,输出B
void count_sort(int A[], int B[], int nLen) {
  //1.找出待排序的数组中最大和最小的元素
  int k = INT_MIN;
  for (int i = 0; i < nLen; i++) {
    if (A[i] > k) {
      k = A[i];
    }
  }
  //===============
  int *C = new int [k];//统计的暂存数组
  //初始化C
  for (int i = 0; i < k; i ++) {
    C[i] = 0;
  }
  //2.统计数组中每一个值为i的元素出现的次数,存入数组C的第i项

  //统计j的次数
  for (int j = 0; j < k; j++){
    C[A[j]] = C[A[j]] + 1;//统计A[j]出现了多少次
  }

  //3.对全部的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  for (int i = 0; i < k; i++) {
    C[i] = C[i] + C[i-1];//对于给定的输入序列中的每个元素x,肯定该序列中值小于x的元素的个数
  }

  //4.反向填充目标数组:将每一个元素i放在新数组的第C(i)项,每放一个 元素就将C(i)减去1
  //逆向遍历源数组(保证稳定性),根据计数数组中对应的值填充到先的数组中
  for (int j = nLen; j>=0; j++) {
    B[C[A[j]]] = A[j];
    C[A[j]] = C[A[j]] -1;
  }
  delete[] C;
}
int main()
{
  int a[] = {5,9,3,9,10,9,2,4,13,10};
  const size_t sz = sizeof(a)/sizeof(a[0]);
  for (int i = 0; i < sz;  i++ ) {
    std::cout << a[i] << " ";
  }
}

 

基数排序:排序

基数排序是首先按最低有效位数字进行排序的,它从低位到高位进行排序。它是一种稳定性的算法。it

相关文章
相关标签/搜索