• Hark的数据结构与算法练习之计数排序


    算法说明

    计数排序属于线性排序,它的时间复杂度远远大于常用的比较排序。(计数是O(n),而比较排序不会超过O(nlog2nJ))。

    其实计数排序大部分很好理解的,唯一理解起来很蛋疼的是为了保证算法稳定性而做的数据累加,大家听我说说就知道了:

    1、首先,先取出要排序数组的最大值,假如我们的数组是int[] arrayData = { 2, 4, 1, 5, 6, 7, 4, 65, 42 };,那么最大值就是65.(代码17-21行就是在查找最大值)

    2、然后创建一个计数数组,计数数组的长度就是我们的待排序数组长度+1。即65+1=66。计数数组的作用就是用来存储待排序数组中,数字出现的频次。 例如,4出现了两次,那么计数数组arrayCount[4]=2。 OK,现在应该明白为什么计数数组长度为什么是66而不是65了吧? 因为为了存储0

        然后再创建一个存储返回结果的数组,数组长度与我们的原始数据长度是相同的。(24和26行)

    3、进行计数(代码29至31行)

    4、将计数数组进行数量累计,即arrayCount[i]+=arrayCount[i-1](代码35行至代码37行)。 

       目的是为了数据的稳定性, 这块我其实看了许久才看懂的…再次证明我的资质真的很差劲。 我来尽力解释一下:

         其实这个与后边那步结合着看理解起来应该更容易些。

         例如我们计数数组分别是 1 2 1 2 1 的话,那么就代表0出现了一次,1出现了两次,2出现了一次,3出现了两次。

      这个是很容易理解的。 那我们再换个角度来看这个问题。

      我们可以根据这个计数数组得到每个数字出现的索引位置,即数字0出现的位置是索引0,数字1出现的问题是索引1,2;数字2出现的位置是索引3,数字4出现的位置是索引4,5。。。。

      OK,大家可以看到,这个索引位置是累加的,所以我们需要arrayCount[i]+=arrayCount[i-1]来存储每个数字的索引最大值。 这样为了后边的输出

    5、最后,把原始数据从后往前输出;然后每个数字都能找到计数器的最后实现索引。  然后将数字存储在实际索引的结果数组中。 然后计数数组的索引--, 结果就出来了。

    PS:计数排序其实是特别吃内存的,所以应用场景是最大值确定并且不大,必须是正整数。 

    时间复杂度:

    O(n+k)  

    请对照下方代码:因为有n的循环,也有k的循环,所以时间复杂度是n+k

    空间复杂度:

    O(n+k)  

    请对照下方代码:需要一个k+1长度的计数数组,需要一个n长度的结果数组,所以空间复杂度是n+k

    代码

    使用的是java

    /*
     * 计数排序
     */
    public class CountingSort {
    	public static void main(String[] args) {
    		int[] arrayData = { 2, 3, 1, 5, 6, 7, 4, 65, 42 };
    		int[] arrayResult = CountintSort(arrayData);
    		for (int integer : arrayResult) {
    			System.out.print(integer);
    			System.out.print(" ");
    		}
    	}
    
    	public static int[] CountintSort(int[] arrayData) {
    		int maxNum = 0;
    		// 取出最大值
    		for (int i : arrayData) {
    			if (i > maxNum) {
    				maxNum = i;
    			}
    		}
    
    		// 计数数组
    		int[] arrayCount = new int[maxNum + 1];
    		// 结构数组
    		int[] arrayResult = new int[arrayData.length];
    
    		// 开始计数
    		for (int i : arrayData) {
    			arrayCount[i]++;
    		}
    
    		// 对于计数数组进行 i=i+(i-1)
    		// 目的是为了保证数据的稳定性
    		for (int i = 1; i < arrayCount.length; i++) {
    			arrayCount[i] = arrayCount[i] + arrayCount[i - 1];
    		}
    
    		for (int i = arrayData.length - 1; i >= 0; i--) {
    			arrayResult[arrayCount[arrayData[i]] - 1] = arrayData[i];
    			arrayCount[arrayData[i]]--;
    		}
    
    		return arrayResult;
    
    	}
    }
    

    结果

    1 2 3 4 5 6 7 42 65 
    

    参考:

    http://blog.csdn.net/sjin_1314/article/details/8655061

    http://www.cnblogs.com/eaglet/archive/2010/09/16/1828016.html

  • 相关阅读:
    正经学C#_循环[do while,while,for]:[c#入门经典]
    Vs 控件错位 右侧资源管理器文件夹点击也不管用,显示异常
    asp.net core 获取当前请求的url
    在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be
    用orchard core和asp.net core 3.0 快速搭建博客,解决iis 部署https无法登录后台问题
    System.Data.Entity.Core.EntityCommandExecution The data reader is incompatible with the specified
    初探Java设计模式3:行为型模式(策略,观察者等)
    MySQL教程77-CROSS JOIN 交叉连接
    MySQL教程76-HAVING 过滤分组
    MySQL教程75-使用GROUP BY分组查询
  • 原文地址:https://www.cnblogs.com/hark0623/p/4349350.html
Copyright © 2020-2023  润新知