堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。
可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。
在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
堆排序首先将待排序的数组存入堆中,并将堆构造为最大/最小堆。再依次从堆中取出堆顶元素,从而得到有序数组。
构造堆时,所用的方法为从最底层有子节点的节点开始依次向上处理。
取出顶元素恢复堆时则是先将末尾元素与顶元素交换位置,在对顶元素进行下沉处理即可。
堆排序是不稳定排序。即相同的元素再经过堆排序后,其先后位置可能发生变化。
堆排序的时间复杂度为N*logN。
Python的代码实现如下:
# -*- coding: utf-8 -*-
#用列表表示一个堆,其中列表中索引为0的位置为空。从索引1开始存放元素。
def parent(i): #在堆中,某个节点的父节点为其索引值整除2。例如索引为4的父节点的索引为2。索引为9的父节点的索引为4。
return i/2
def left(i): #某个节点的左子节点的索引为i*2
return i*2
def right(i): #某个节点的右子节点的索引为i*2+1
return i*2+1
class Heap: #堆的数据结构类
def __init__(self, heapList=[None]): #对堆进行初始化。没有给堆初始列表时,初始化为仅包含一个None元素的列表。
self.heapList = [None] + heapList #有初始化列表时,堆列表为初始化列表前插入None元素
def max_heapfy(self, i): #表明对i节点进行最大堆恢复
if (i*2) > self.length-1: #该元素没有子节点时
maxIndex = i
elif (i*2+1) > self.length-1: #该元素只有左节点时
maxIndex = left(i)
elif self.heapList[left(i)] > self.heapList[right(i)]: #该元素同时有左右节点,且左节点的值大于右节点时
maxIndex = left(i)
else: #该元素同时有左右节点,且左节点的值小于右节点时
maxIndex = right(i)
if self.heapList[i] < self.heapList[maxIndex]: #当其子节点值大于其节点值时:
self.heapList[i], self.heapList[maxIndex] = self.heapList[maxIndex], self.heapList[i]
#交换其子节点的值和其值
self.max_heapfy(maxIndex) #并对其子节点进行最大堆化
def build_max_heap(self): #构建最大堆
self.length = len(self.heapList) #计算堆的大小(包含第一个空元素)
for i in range(self.length/2, 0, -1): #从包含子节点的节点开始依次向上遍历
self.max_heapfy(i)
def insert(self, k): #向堆内插入元素
self.length += 1 #堆的规模加1
self.heapList.append(float("-inf")) #向堆内插入一个负无穷的数
self.increase_key(self.length, k) #增加元素
def maxinum(self): #查询堆内最大元素,即为索引为1的元素值。
return self.heapList[1]
def extract_max(self): #弹出堆内最大元素。
maxValue = self.heapList[1] #取得最大元素值
self.heapList[1] = self.heapList[self.length] #将末尾元素移至堆头
del self.heapList[self.length] #删除末尾元素
self.length -= 1 #将堆的规模减1
self.max_heapfy(1) #对堆顶元素最大堆化
return maxValue
def increase_key(self, x, k): #增加元素
self.heapList[x] = k #将新增的负无穷位置赋予插入值
while x > 1 and self.heapList[parent(x)] < self.heapList[x]: #当元素索引大于1且其值大于其父节点值
self.heapList[parent(x)], self.heapList[x] = self.heapList[x], self.heapList[parent(x)]
#交换其值和其父节点的值
x = parent(x) #继续对其父节点进行判断
def show(self): #展示堆
print "the length of queue is", self.length - 1
print "the heapList is", self.heapList[1:]
def heapSort(unsortedList):
heap = Heap(unsortedList) #将乱序列表转换为堆
heap.build_max_heap() #将堆构建为最大堆
print heap.heapList
print "*************heap has been build up*********"
for i in range(len(unsortedList), 1, -1):
heap.heapList[i], heap.heapList[1] = heap.heapList[1], heap.heapList[i] #将末尾节点与根节点进行交换,
#交换完成后,i位置的节点为当前堆中最大的元素。即每次循环中得到的i索引的元素为已有序的列表。
heap.length -= 1 #未排序的堆的规模减小1
heap.max_heapfy(1) #此时,根节点不满足最大堆的要求,需要对堆进行最大堆恢复
return heap.heapList[1:]
if __name__ == '__main__':
list1 = [3,2,4,6,7,5,1,8,10,9]
list2 = ["wang", "zhe", "tian", "jin", "da", "xue"]
ordered_list1 = heapSort(list1)
ordered_list2 = heapSort(list2)
print ordered_list1 #[2, 3, 4, 5, 6, 7]
print ordered_list2 #['da', 'jin', 'tian', 'wang', 'xue', 'zhe']