Python implementation of the heap sort

Heap sort algorithm of python

Note: this article node and the node of the used indistinctly

The concept of the heap:

  • Heap is a complete binary tree
  • Value of each non-leaf node must be greater than or equal to the left and right child nodes is called a heap big top
  • Value of each non-leaf node to be equal to or smaller than the left and right child nodes is called a small stack top
  • The root node must be the maximum stack big top, the top of the stack must be a minimum of a small
    stack is actually observed value from the node, the node value of a complete binary tree having a characteristic point

Heap type

According to the characteristics of the heap, we can pile into two categories

  • Large stack top
    of each non-leaf node of the binary tree which are greater than or equal to the value of the left and right child nodes, the root node must be the largest value in the stack top, FIG. 1
    figure 1

  • Small top stack
    each non-leaf node to be equal to or smaller than the left and right child node value, a minimum value must be large root stack top, as shown in FIG 2

Heapsort step

Construction of complete binary tree

Original data: 30,20,80,40,50,10,60,70,90
construct a complete binary tree to store data, depending on the nature and the elements 5 complete binary numbers: the sequence of data structures into a list is configured [0,30,20,80,40,50,10,60,70,90] (a 0 is inserted, to the node and the array index complete binary numbers coincide), as in FIG.

Construction of a large pile top

How to build a queue to be larger than the top of the stack (or a small heap top), heap sort algorithm is the core of
the analysis
1. A 2 of degree of the node, if the maximum value of his left and right child nodes is greater than its maximum value of the node and the exchange
2. the degree of the node a 1 if he's left child is greater than its value, then the switch
3. If node a is switched to a new location (in this case the node a that already had a a child node, it is necessary to a new position, whether firmly secured, children need their junction point comparison), but also other children nodes, and repeat the above process

1. Construction of the large top stack - choose the starting node
from the parent node of the last complete binary tree node starts, i.e., the parent node finally the rightmost leaf node of the layer is started, if the number of nodes is n, the initial node 2 // n-number, which will ensure that each comparison process, to be able to give all the numbers are relatively (the stack is the start position 9 @ 2 = 4)

2. Construction of the large top stack - selects the next node
to find the start from the starting point to the left of its junction with the layer node from the head and then the layer of the rightmost node starts further to the left by one search, until roots node, as shown below, the order is: 4,3,2,1

3. Large stack top target
value ensures that the value of each node point greater than about junction

A more chaotic can be seen in FIG.

Sequence

Analysis
1. The maximum root large top stack and the last leaf node exchange, the last point is the maximum value of a leaf node, this leaf node to be excluded from the sorting node
2 from the root after the start (a new root node), readjusted to the top of the heap large, repeat the previous step
to ask: ordering, top of the heap and the last node exchange, and eliminate the last node, why you changed it last?
A: The top of the heap of data has confirmed that this is the maximum (minimum) value, and then there is nothing left in the tree, and placing it on the last leaf node, good marks necessary.

to sum up

1.利用堆性质的一种选择排序,在堆顶选出最大值或者最小值(这也就是可以解决我们常见的TopN问题)
2.时间复杂度为O(nlogn)
3.空间复杂度:只是使用了一个交换用的空间,所以空间复杂度为O(1)
4.堆排序是一种不稳定的排序算法

Note: Since the heap sort state is not sensitive to the sort of the original recording, whether it is the best and the worst, the time complexity is O (nlogn)

Code

#!/bin/env python
# -*- coding: utf-8 -*-
'''
__title__ = ''
__author__ = 'cxding'
__mtime__ = '2020/1/3'
# code is far away from bugs with the god
'''
import math

#居中打印  数量少的可以这么打印,多了就不行了
def print_tree(array,unit_width=2):
    length = len(array)
    depth = math.ceil(math.log2(length + 1))

    index = 0

    width = 2 ** depth -1 #行宽,最深的行 15个数
    for i in range(depth):
        for j in range(2 ** i):
            #居中打印,后面追加一个空格
            print('{:^{}}'.format(array[index],width * unit_width),end=' ' * unit_width)
            index += 1
            if index >= length:
                break
        width = width // 2 #居中打印宽度减半
        print()


def sift(li:list,low:int,high:int):
    '''
    调整当前结点,这个时间复杂度最多是一棵树的高度,所以是logn
    :param li: 列表
    :param low: 堆的根结点位置
    :param high: 堆的最后一个元素的位置
    :return:
    '''

    i = low
    j = 2 * i + 1 #j开始是左孩子

    tmp = li[low] #把堆顶存起来

    while j <= high: #只要j位置有数,没有超过堆的长度
        if j + 1 <= high and  li[j+1] > li[j]:
            j = j + 1 # 如果有右孩子,并且他的值比左孩子大,将j指向右孩子

        if li[j] > tmp:
            li[i] = li[j]
            i = j
            j = 2 * i + 1
        else:
            li[i] = tmp
            break
    else:
        li[i] = tmp

    #return li


li = [10,40,50,30,20,90,70,80,60]


def heap(li):
    '''
    实现堆排序,这里面的时间复杂度是nlogn,所以最终的时间复杂度就是nlogn,但是这个速度会比快排慢
    :param li: 待排序的列表
    :return:
    '''
    #构建大顶堆
    n = len(li)
    print("原始的序列为:")
    print_tree(li)
    for i in range(n//2 - 1,-1,-1):
        print('-' * 30)
        sift(li,i,n-1)#high为n-1,其实是取了极大值
        print_tree(li)
    print("准备出数了!")
    #挨个出数
    for i in range(n-1,-1,-1):
       #将第一个元素和堆的最后一个元素交换
        li[0],li[i] = li[i],li[0]
        sift(li,0,i -1)#将最后一个元素排除在外,只需要调整堆顶的元素就是一个大顶堆了
        print('-'*30)
        print_tree(li)

heap(li)

Yet another wording:

#!/bin/env python
# -*- coding: utf-8 -*-
'''
__title__ = ''
__author__ = 'cxding'
__mtime__ = '2020/1/13'
# code is far away from bugs with the god
'''

origin = [0,30,20,80,50,10,60,70,90]

total = len(origin) - 1

def heap_adjust(n,i,array:list):
    '''
    调整当前结点,主要是为了保证以i为堆顶的堆是一个大顶堆(或者小顶堆)
    :param n: 待排序的序列的总长度
    :param i: 当前结点,因为要是一个堆,所以他必须至少有一个子结点
    :param array: 待排序的列表
    :return:

    '''

    while 2 * i <= n:
        lchild_index = 2 * i

        if lchild_index < n and array[lchild_index] < array[lchild_index + 1]:#如果有右孩子,并且右孩子的值比左孩子大
            #array[i],array[lchild_index + 1] = array[lchild_index + 1],array[i]
            lchild_index += 1
        if array[lchild_index] > array[i]:#接上面,已经得到了左右结点中最大结点的index,只要将其与当前结点比较,得到最大的直接就可以了,
            # 如果当前结点就是最大的,就不用比较了,这棵子树就是大顶堆了,这是有前提的,前提是认定了,已经从len(li) // 2开始进行了一次次向上了
            array[i],array[lchild_index] = array[lchild_index],array[i]
            i = lchild_index
        else:
            break


#调整成大顶堆
for i in range(total//2,0,-1):
    heap_adjust(total,i,origin)

'''

heap_adjust(total,4,origin)
print(origin)

heap_adjust(total,3,origin)
print(origin)

heap_adjust(total,2,origin)
print(origin)

heap_adjust(total,1,origin)
print(origin)
#[0, 90, 50, 80, 30, 10, 60, 70, 20]
'''
print(origin)
#[0, 90, 50, 80, 30, 10, 60, 70, 20]

def heap(max_heap:list):
    length = len(max_heap) - 1
    print("length ---> ",length)
    print("origin--->",max_heap)
    for i in range(length,1,-1):
        print("i-->",i,"element--",max_heap[i])
        max_heap[1],max_heap[i]= max_heap[i],max_heap[1]
        heap_adjust(i-1,1,max_heap)

heap(origin)
print(origin)

Guess you like

Origin www.cnblogs.com/dingcx/p/12191944.html