算法导论第八章 -- 计数排序

来源:互联网 发布:照片抠图软件 编辑:程序博客网 时间:2024/06/05 00:33

1.算法基本思想:对于在待排序的数组里面的数字,记录小于它的元素的个数,那么记录下来的这个数字就是它在输出数组里面的位置了

这里假设元素是互异的。

2.如果元素不互异,那么就要对算法里面的一个记录数组作一些操作,以便保持算法的正确性。


代码如下:


countSort.h

#ifndef COUNTSORT_H#define COUNTSORT_H#include <iostream>#include <vector>std::vector<int> countSort(std::vector<int>&);void printVector(std::vector<int>&);int getMax(std::vector<int>&);#endif


其中,第一个函数是算法,第二个函数方便打印数组,第三个函数得到数组中的最大值

为何要得到最大值:在下面解释。


#include "countSort.h"int getMax(std::vector<int>& target)     //遍历数组,找到最大值{int max = 0;for (std::vector<int>::size_type i = 0; i != target.size(); ++i){if (target[i] > max){max = target[i];}}return max;}void printVector(std::vector<int>& target)       //打印数组{for (std::vector<int>::size_type i = 0; i != target.size(); ++i){std::cout << target[i] << " ";}std::cout << std::endl;}std::vector<int> countSort(std::vector<int>& target)     //计数排序{typedef std::vector<int>::size_type index;int maxElement = getMax(target);std::vector<int> result(target.size(),0);       //新开两个数组,一个用来记录元素的个数std::vector<int> count(maxElement + 1,0);//另外一个用来装结果for (index i = 0; i != target.size(); ++i)     //解释点1{count[target[i]] += 1;}for (index i = 1; i!= count.size(); ++i)      // 解释点2{count[i] += count[i-1];}for (index i = 0; i != target.size(); ++i)       //解释点3{result[count[target[i]] - 1] = target[i];count[target[i]] -= 1;}return result;}



在计数排序中,我们需要两个临时数组来辅助,第一个数组count是用来记录每一个元素出现的个数,并且要对这个数组进行一定的运算得到

原来数组内小于等于这个数组下标数字的元素的个数。就相当于:count这个数组的下标表示可能在原来数组中的元素,而存储在count

中的数字是对应下标数字出现的次数。

例: count[5] = 7:代表在原数组中,5这个数字出现了7次。

解释点1:

遍历要排序的数组,然后把数组里面的元素出现的次数记录在辅助数组相应的位置

解释点2:

把辅助数组重构:从第二个元素开始,把当前元素加上上一个元素的值,相当于:在待排序的数组里,小于这个下标的元素的个数。

解释点3:

从原始数组的第一个元素开始,用这个元素在辅助数组里面找到小于这个值的元素的个数,然后把原始数组的当前元素赋值到输出数组的相应位置。

因为待排序的数组元素个数已经少一个了,并且考虑原始数组里面有重复元素的情况,那么就要把当前辅助数组相应位置的值减1,表示等于

这个下标的值的元素已经少了一个。

并且在辅助数组中,元素的值必然是大于等于0的,等于0没有关系,因为不会再索引到这个值。



main.cpp



#include "countSort.h"int main(){int a[11] = {6,0,2,0,1,3,4,6,1,3,100000};std::vector<int> v(a,a+11);std::vector<int> r = countSort(v);printVector(r);return 0;}

可以得到正确的排序结果。




缺点:相对于其他原址排序的算法(堆排序,快排),这个排序算法会用到额外的空间,并且如果数组中的最大值很大很大的时候,那么辅助数组

   的利用率会很低,比如说:

   我们有一个待排序的数组:[1000000,1],就两个元素,但是最大值是1000000,所以辅助数组的长度就是1000001,用上面的方法操作

   这个数组的时间会上升很多。按照书上的伪代码:k这个值是可以被辅助数组索引到的,那么为了让程序不会抛出out_of_range 的异常的话,

   那么就只能找出原始数组里面的最大值,并且把辅助数组的长度初始化为这个最大值加1,才能保证   count[ target[ i ] ]这一语句的正确性。

并且待排序的数组里面的元素只能是大于等于0的整数(保证能正确索引)









0 0
原创粉丝点击