Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析。同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择对这个算法进行分析主要是因为它用到了一个非常有意思的算法技巧:数据结构 - 堆。而且堆排其实是一个看起来复杂其实并不复杂的排序算法,个人认为heapsort在机器学习中也有重要作用。这里重新详解下关于Heapsort的方方面面,也是为了自己巩固一下这方面知识,有可能和其他的文章有不同的入手点,如有错误,还请指出。文中引用的referecne会再结尾标注。

p.s. 个人认为所谓详解是你在看相关wiki或者算法书看不懂的时候看通俗易懂的解释,不过最佳方案还是去看教授们的讲解,推荐reference[1]中的heapsort章节。

 

以上是废话,可以不看

 


 Section 1 - 简介

Heapsort是一个comparison-based的排序算法(快排,归并,插入都是;counting sort不是),也是一种选择排序算法(selection sort),一个选择算法(selection algorithm)的定义是找到一个序列的k-th order statistic(统计学中的术语),直白的说就是找到一个list中第k-th小的元素。以上都可以大不用懂,heapsort都理解了回来看一下是这回事就是了。同样,插值排序也是一种选择排序算法。

 

Heapsort的时间复杂度在worst-case是\(O(nlgn)\),average-case是\(O(nlgn)\);空间复杂度在worst-case是\(O(1)\),也就是说heapsort可以in-place实现;heapsort不稳定。

 

以下顺便附上几种排序算法的时间复杂度比较(\(\Theta-notation\)比\(O-notation\)更准确的定义了渐进分析(asymptotic analysis)的上下界限,详细了解可以自行google):

Table 1 - 四种排序算法的running time比较
Algorithm

Worst-case

Average-case/expected 

Insertion sort(插值排序)

 \(\Theta (n^2)\)  \(\Theta (n^2)\)

Merge sort(归并排序)

 \(\Theta (nlgn)\)  \(\Theta (nlgn)\)
Heapsort(堆排序)  \(O(nlgn)\)  \(O(nlgn)\)
Quicksort(快速排序)  \(\Theta (n^2)\)  \(\Theta (n^2)\) (expected)

*Additional Part - KNN

heapsort在实践中的表现经常不如quicksort(尽管quicksort最差表现为 \(\Theta (n^2)\),但quicksort 99%情况下的runtime complexity为 \(\Theta (nlgn)\)),但heapsort的\(O(nlgn)\)的上限以及固定的空间使用经常被运作在嵌入式系统。在搜索或机器学习中经常也有重要的作用,它可以只返回k个排序需要的值而不管其他元素的值。例如KNN(K-nearest-neighbour)中只需返回K个最小值即可满足需求而并不用对全局进行排序。当然,也可以使用divide-and-conquer的思想找最大/小的K个值,这是一个题外话,以后有机会做一个专题比较下。

以下程序为一个简单的在python中调用heapq进行heapsort取得k个最小值,可以大概体现上面所述的特性:

 1 '''
 2 Created On 15-09-2014
 3 
 4 @author: Jetpie
 5 
 6 '''
 7 
 8 
 9 import heapq, time
10 import scipy.spatial.distance as spd
11 import numpy as np
12 
13 pool_size = 100000
14 
15 #generate an 3-d random array of size 10,000
16 # data = np.array([[2,3,2],[3,2,1],[2,1,3],[2,3,2]])
17 data = np.random.random_sample((pool_size,3))
18 #generate a random input
19 input = np.random.random_sample()
20 #calculate the distance list
21 dist_list =  [spd.euclidean(input,datum) for datum in data]
22 
23 #find k nearest neighbours
24 k = 10
25 
26 #use heapsort
27 start = time.time()
28 heap_sorted = heapq.nsmallest(k, range(len(dist_list)), key = lambda x: dist_list[x])
29 print('Elasped time for heapsort to return %s smallest: %s'%(k,(time.time() - start))) 
30 
31 #find k nearest neighbours
32 k = 10000
33 
34 #use heapsort
35 start = time.time()
36 heap_sorted = heapq.nsmallest(k, range(len(dist_list)), key = lambda x: dist_list[x])
37 print('Elasped time for heapsort to return %s smallest: %s'%(k,(time.time() - start)))
get_k_smallest

相关文章:

  • 2021-12-02
  • 2021-07-14
  • 2021-09-28
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-12-24
  • 2022-01-03
  • 2022-12-23
  • 2021-09-03
  • 2021-08-02
  • 2021-09-03
  • 2021-12-31
相关资源
相似解决方案