排序问题之计数排序

排序问题

算法问题的基础问题之一,便是排序问题:

  输入:n个数的一个序列,<a1, a2,..., an>。

  输出:一个排列<a1',a2', ... , an'>,满足a1' ≤ a2' ≤... ≤ an' 。(输出亦可为降序,左边给出的例子为升序)

一.算法描述

  计数排序假设输入一个长度为n的序列,每一个都是0到k之间的整数,其中k为某个常数整数。当k=O(n)时,排序的时间复杂度为O(n)。

  对于A[1,n],我们首先分配一个输出结果的空间B[1,n],然后还需要一个计数数组C[0,k]。首先我们遍历原序列A[1,n],将区间[0,k]内每一个整数出现的次数累积统计到C中,然后从头开始将C中的每一个位置上的计数与前一位置累加。最后从尾至头遍历A,将对应的值val存放到B[C[val]]中,并且C[val]减一,一趟遍历后完成排序。

二.代码实现

      下面是插入排序的C++实现:

#include<iostream>
#include<vector>
using namespace std;
//计数排序
void countingsort(vector<int> &v, int k)
{
    //初始化
    vector<int> temp(v.size(),0);
    vector<int> c(k + 1,0);

    
    
    //遍历一遍原数组,计数与c[k]中
    for(int i = 0; i < v.size(); i++)
    {
        c[v[i]] = c[v[i]] + 1;
    }
    //将c[k]中的计数累和
    for(int i = 1; i <= k + 1; i++)
    {
        c[i] = c[i] + c[i-1];
    }
    
    //将计数的元素存到temp中
    for(int j = v.size() - 1; j >= 0; j--)
    {
        temp[c[v[j]] - 1] = v[j];
        c[v[j]]--;
    }
    //把排序后的temp赋给v
    v = temp;

}

int main()
{
    int arr[] = { 1, 2, 6, 4, 3, 5, 2, 6, 3, 4, 5 ,6};
    vector<int> v(arr, arr + sizeof(arr)/sizeof(int));
    int k = 6;

    countingsort(v, k);

    copy (v.begin(), v.end(), ostream_iterator<int> (cout, " "));
    cout << endl; 
}
View Code

 

 

三.算法分析

(1)时间复杂度

  由于我们要遍历两次A和一次C,时间复杂度为θ(k + n)。当k=θ(n)时,使用计数排序的时间复杂度就为θ(n),同样也是o(n)。

(2)稳定性

   稳定。对于A中的同值元素x与x,由于我们往B中填入元素时是对A从尾至头遍历的,所以位于后面的x对应的C[x]值会更大,因而会填入到B中更靠后的位置,所以B中的同值元素顺序与A中相同,所以计数排序是稳定的排序算法。

(3)适合范围

        知道序列中的最大最小值,且最值等于θ(n)时适用。

posted @ 2019-05-24 17:49  バニー  阅读(222)  评论(0编辑  收藏  举报