11 Sep 2019
堆排序算法
堆排序算法
基础知识可见:堆排序(大顶堆、小顶堆)—-C语言
思路:(大/小顶堆)先保证父节点大/小于子节点,之后从后往前递归调整位置。
1.第一个过程-调整结点
假如有10个数据,序号的排列如下:
0
1 2
3 4 5 6
7
可以整理出来一层的父子结点关系如下所示:
0 1 2
1 3 4
2 5 6
3 7
从上数据可以看出来,父结点的索引为0、1、2、3、4,可以推导出:
- 左结点索引为$left\ \ =parent × 2 + 1$
- 右结点索引为$right=left+1$
2.第二个过程-排序
不断的循环,将当前循环的最大/小值换到数组的最后。
代码实现
Python实现
class HeapSort:
@staticmethod
def __endian(arr, start, end, compare_func):
# 根结点
root = start
# 左孩子
child = root * 2 + 1
print("start:%s, end:%s, root:%s, left:%s
-> %s" % (start, end, root, child, arr))
while child <= end:
# 判断左右结点的大小,选择其中一个与父结点比较
if child + 1 <= end and compare_func(arr[child], arr[child + 1]):
child += 1
# 与父节点比较
if compare_func(arr[root], arr[child]):
arr[root], arr[child] = arr[child], arr[root]
root = child
child = root * 2 + 1
else:
break
@staticmethod
def __big_endian(left_child, right_child):
return left_child < right_child
@staticmethod
def __small_endian(left_child, right_child):
return left_child > right_child
@staticmethod
def __heap_sort(arr, compare_func):
# 无序区大根堆排序
first = len(arr) // 2 - 1
for start in range(first, -1, -1):
# 从下到上,从左到右对每个节点进行调整,循环得到非叶子节点,调整所有的节点
HeapSort.__endian(arr, start, len(arr) - 1, compare_func)
for end in range(len(arr) - 1, 0, -1):
# 顶部尾部互换位置
arr[0], arr[end] = arr[end], arr[0]
# 重新调整子节点的顺序,从顶开始调整
HeapSort.__endian(arr, 0, end - 1, compare_func)
return arr
@staticmethod
def big_heap_sort(arr):
return HeapSort.__heap_sort(arr, HeapSort.__big_endian)
@staticmethod
def small_heap_sort(arr):
return HeapSort.__heap_sort(arr, HeapSort.__small_endian)
def main():
array = [5, 3, 2, 1, 9, 8, 4, 0]
print("堆排序(大顶堆):%s" % HeapSort.big_heap_sort(array))
print("堆排序(小顶堆):%s" % HeapSort.small_heap_sort(array))
输出结果
start:3, end:7, root:3, left:7 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:2, end:7, root:2, left:5 -> [0, 1, 2, 9, 4, 5, 8, 3]
start:1, end:7, root:1, left:3 -> [0, 1, 8, 9, 4, 5, 2, 3]
start:0, end:7, root:0, left:1 -> [0, 9, 8, 3, 4, 5, 2, 1]
start:0, end:6, root:0, left:1 -> [1, 4, 8, 3, 0, 5, 2, 9]
start:0, end:5, root:0, left:1 -> [2, 4, 5, 3, 0, 1, 8, 9]
start:0, end:4, root:0, left:1 -> [1, 4, 2, 3, 0, 5, 8, 9]
start:0, end:3, root:0, left:1 -> [0, 3, 2, 1, 4, 5, 8, 9]
start:0, end:2, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:1, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:0, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
堆排序(大顶堆):[0, 1, 2, 3, 4, 5, 8, 9]
start:3, end:7, root:3, left:7 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:2, end:7, root:2, left:5 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:1, end:7, root:1, left:3 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:7, root:0, left:1 -> [0, 1, 2, 3, 4, 5, 8, 9]
start:0, end:6, root:0, left:1 -> [9, 1, 2, 3, 4, 5, 8, 0]
start:0, end:5, root:0, left:1 -> [8, 3, 2, 9, 4, 5, 1, 0]
start:0, end:4, root:0, left:1 -> [8, 3, 5, 9, 4, 2, 1, 0]
start:0, end:3, root:0, left:1 -> [8, 4, 5, 9, 3, 2, 1, 0]
start:0, end:2, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
start:0, end:1, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
start:0, end:0, root:0, left:1 -> [9, 8, 5, 4, 3, 2, 1, 0]
堆排序(小顶堆):[9, 8, 5, 4, 3, 2, 1, 0]
附录
- 堆仅仅使用数组,且不使用指针,空间占用小。
- 时间复杂度:$O(nlog_2n)$
- 空间复杂度:$O(1)$
- 稳定性:不稳定
博文
- 堆排序算法详解:文章的动图演示不错。
- 图解排序算法(三)之堆排序
- 各个排序算法的时间复杂度和稳定性,快排的原理
Til next time,
LinkWorld
at 22:54