第十六章 Caché 算法与数据结构 计数排序

文章目录

  • 第十六章 Caché 算法与数据结构 计数排序
  • 定义
  • 使用场景
  • 简单示例
    • 计数类
    • 调用
  • 优化
    • 问题
    • 解决
    • 优化版本
      • 计数类
      • 调用
  • 时间复杂度
  • 空间复杂度

第十六章 Caché 算法与数据结构 计数排序

定义

  • 假设20个随机整数的值如下所示。9,3,5,4,9,1,2,7,8,1,3,6,5,3,4,0,10,9 ,7,9。
  • 在0到10之间取值。数组定义大小为取值的最大范围
  • 下面就开始遍历这个无序的随机数列,每一个整数按照其值对号入座,同时, 对应数组下标的元素进行加1操作。
  • 例如第1个整数是9,那么数组下标为9的元素加1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7g9EKxnO-1592700881458)(FFE7AFBDB0A24BAC9B37C1925AD0BFE9)]

  • 第2个整数是3,那么数组下标为3的元素加1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gDYPKHHf-1592700881459)(76C6868413C5487FABDE9AC4D6D37515)]

  • 继续遍历数列并修改数组……,最终,当数列遍历完毕时,数组的状态如下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vHUomUc-1592700881460)(EC8234E10452450E98BE52BA2F732FB5)]

  • 该数组中每一个下标位置的值代表数列中对应整数出现的次数。
  • 有了这个统计结果,排序就很简单了。直接遍历数组,输出数组元素的下标值,元素的值是几,就输出几次。
    0,1,1,2,3,3,3,4,4,5,5,6,7,7,8,9,9,9,9,10 显然,现在输出的数列已经是有序的了。

使用场景

  • 它适用于一定范围内的整数排序。在取值范围不是很大的情况下,它的性能甚至快过那些时间复杂度为O(nlogn)的排序。
  • 当数列最大和最小值差距过大时,并不适合用计数排序。
  • 当数列元素不是整数时,也不适合用计数排序。

简单示例

计数类

Class PHA.YX.Arithmetic.CountSort Extends %RegisteredObject
{

Method sort(array As PHA.YX.Arithmetic.Array)
{
	/* 1.得到数列的最大值 */
	#dim max as %Integer  = array.get(0)
	for i = 1 : 1 : (array.length() - 1) {
		if (array.get(i) > max){
			s max = array.get(i)
		}
	}
	
	/* 2.根据数列最大值确定统计数组的长度 */
	#dim countArray as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d countArray.init(max + 1)
	
	/* 3.遍历数列,填充统计数组 */
	for i = 0 : 1 : (array.length() - 1) {
		if (countArray.get(array.get(i)) = ""){
			d countArray.set(array.get(i), 0)
		}else{
			d countArray.set(array.get(i), (+countArray.get(array.get(i)) + 1))
		}
		
	}
	b ;countArray
	/* 4.遍历统计数组,输出结果 */
	#dim index as %Integer = 0
	#dim sortedArray as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d sortedArray.init(array.length())
	
	for i = 0 : 1 : (countArray.length() - 1) {
		for j = 0 : 1 : (countArray.get(i) ){
			d sortedArray.set(index, i)
			s index = index + 1
		}
	}
	b ;sortedArray
	q sortedArray
}
}

调用

/// w ##class(PHA.YX.Arithmetic).CountSort()
ClassMethod CountSort()
{
	#dim array as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d array.init(13)
	d array.insert(0,4)
	d array.insert(1,4)
	d array.insert(2,6)
	d array.insert(3,5)
	d array.insert(4,3)
	d array.insert(5,2)
	d array.insert(6,8)
	d array.insert(7,1)
	d array.insert(8,7)
	d array.insert(9,5)
	d array.insert(10,6)
	d array.insert(11,0)
	d array.insert(12,10)
	
	#dim countSort as PHA.YX.Arithmetic.CountSort = ##class(PHA.YX.Arithmetic.CountSort).%New() 
	s array = countSort.sort(array)
	
	d array.output()
	
	q ""
}
<BREAK>zsort+30^PHA.YX.Arithmetic.CountSort.1
DHC-APP 3e1>g
0
1
2
3
4
4
5
5
6
6
7
8
9
10
 

优化

问题

  • 我们只以数列的最大值来决定统计数组的长度,其实并不严谨。例如下面的数列。95,94,91,98,99,90,99,93,91,92。
  • 这个数列的最大值是99,但最小的整数是90。如果创建长度为100的数组,那么前面从0到89的空间位置就都浪费。

解决

  • 以最大值减去最小值的差作为数组的长度。
  • 以刚才的数列为例,统计出数组的长度为99-90+1=10,偏移量等于数列的最小值90。

优化版本

计数类

Method optimizeSort(array As PHA.YX.Arithmetic.Array)
{
	/* 1.得到数列的最大值和最小值,并算出差值d */
	#dim max as %Integer = array.get(0)
	#dim min as %Integer = array.get(0)
	for i = 1 : 1 : (array.length() - 1) {
		if (array.get(i) > max){
			s max = array.get(i)
		}
		if (array.get(i) < min){
			s min = array.get(i)
		}
	}
	#dim d as %Integer = max - min
	
	/* 2.创建统计数组并统计对应元素个数 */
	#dim countArray as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d countArray.init(d + 1)
	
	for i = 0 : 1 : (array.length() - 1) {
		if (countArray.get((array.get(i)- min)) = ""){
			d countArray.set((array.get(i) - min), 1)
		}else{
			d countArray.set((array.get(i) - min), (+countArray.get((array.get(i) - min)) + 1))
		}
		
	}
	
	b ;2 countArray
	/* 3.统计数组做变形,后面的元素等于前面的元素之和 */
	for i = 1 : 1 : countArray.length - 1 {
		d countArray.set(i , (countArray.get(i) + countArray.get(i - 1)))
	}
	
	b ;3 countArray
	/* 4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组 */
	#dim sortedArray as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d sortedArray.init(array.length())
	
	for i = (countArray.length() - 1) : -1 : 0  {
		s arrayMin = array.get(i) - min
		s countMin = countArray.get(arrayMin) - 1
		d sortedArray.set(countMin, array.get(i))
		d countArray.set(arrayMin, countMin)
	}
	b ;sortedArray
	q sortedArray
}

调用

/// w ##class(PHA.YX.Arithmetic).OptimizeCountSort()
ClassMethod OptimizeCountSort()
{
	#dim array as PHA.YX.Arithmetic.Array = ##class(PHA.YX.Arithmetic.Array).%New()
	d array.init(10)
	d array.insert(0,95)
	d array.insert(1,94)
	d array.insert(2,91)
	d array.insert(3,98)
	d array.insert(4,99)
	d array.insert(5,90)
	d array.insert(6,99)
	d array.insert(7,93)
	d array.insert(8,91)
	d array.insert(9,92)

	#dim countSort as PHA.YX.Arithmetic.CountSort = ##class(PHA.YX.Arithmetic.CountSort).%New() 
	s array = countSort.optimizeSort(array)
	
	d array.output()
	
	q ""
}
DHC-APP>w ##class(PHA.YX.Arithmetic).OptimizeCountSort()
90
91
91
92
93
94
95
98
99
99

时间复杂度

  • 代码第1、2、4步都涉及遍历原始数列,运算量都是n,第3步遍历统计数列,运算量是m,所以总体运算量是3n+m,去掉系数,时间复杂度是O(n+m)。

空间复杂度

  • 至于空间复杂度,如果不考虑结果数组,只考虑统计数组大小的话,空间复杂度是O(m)。

你可能感兴趣的:(Caché,算法与数据结构)