堆排序与程序实现

2018-11-06  本文已影响0人  统计学徒

堆排序(heapsort)的时间复杂度为O(nlgn),具有空间原址性(任何时候都只需要常数个额外的元素空间存储临时数据)。同时拥有了插入排序和归并排序的优点。

算法:

计算父结点、左右孩子的下标
PARENT(i)
    return [i/2]
LEFT(i)
    return 2i
RIGHT(i)
    return [2i+1]

维护最大堆性质
MAX-HEAPIFY(A,i)
    left = LEFT(i)
    right = RIGHT(i)
    if left <= A.heap_size and A[left] > A[i]
        largest = left
    else 
        largest = i
    if right <= A.heap_size and A[right] > A[largest]
        exchange A[i] with A[largest]
        MAX-HEAPIFY(A,largest)    # 递归调用

建堆
BUILD-MAX-HEAP(A)
    A.heap_size = A.length
    for i = [A.length/2] downto 1
        MAX-HEAPIFY(A,i]

堆排序,将根结点的值(由最大堆性质决定,此值即为堆中最大值)取出,对剩下的数据堆重新维护最大
堆性质,再取出根结点的值,各根结点值从数组尾部倒序放置,如此循环直至结束,则数据从数组头部到
尾部由小到大排列。
HEAPSORT(A)
    BUILD-MAX-HEAP(A)
    for i = A.length downto 2
        exchange A[1] with A[i]
        A.heap_size = A.heap_size - 1
        MAX-HEAPIFY(A,1)

Python 脚本

# 维护父结点保持大于左右孩子的性质
# a 数组,i 结点
def max_heapify(a, i, heapsize):
    # 左孩子
    left = 2*i + 1
    # 右孩子
    right = left + 1
    #print(i, left, right)
    # 比较左孩子和父结点大小,再用其中较大者与右孩子比较
    if(left < heapsize and a[i] < a[left]):
        largest = left
    else:
        largest = i
    if(right < heapsize and a[largest] < a[right]):
        largest = right
    # 如果最大者不是父结点,将父结点与最大者进行交换
    if(largest != i):
        temp = a[i]
        a[i] = a[largest]
        a[largest] = temp
        # 交换之后有可能违反最大堆性质,递归调用维护性质
        max_heapify(a, largest, heapsize)

# 构建最大堆,通过遍历节点,实现根结点是堆数据中的最大值
def build_max_heap(a):
    heapsize = len(a)    
    i = int(heapsize/2) - 1
    # 从后到前,对结点进行遍历维护
    while(i>=0):
        max_heapify(a, i, heapsize)
        i = i - 1
        #print(a)

# 交换函数
def swap(a, i, j):
    temp = a[i]
    a[i] = a[j]
    a[j] = temp

# 构建最大堆之后,根结点处有最大的数,将最大值与最后的数交换取出,再对剩余的 len-1 数据继续重复此操作
def heap_sort(a):
    build_max_heap(a)
    i = len(a) - 1
    while(i>=1):
        swap(a, 0, i)    # 交换根结点和最后一个数
        max_heapify(a, 0, i)
        i = i - 1
        #print(a)

if __name__ == '__main__':
    a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
    print(a)
    #build_max_heap(a)
    heap_sort(a)
    print(a)

C程序:

#include<stdio.h>

// 维护父结点保持大于左右孩子的性质
// a 数组,i 结点, heapsize 堆大小 
void max_heapify(int a[], int i, int heapsize)
{
    int left, right, largest, temp;
    left = 2*i + 1;     // 左孩子下标索引 
    right = left + 1;   // 右孩子下标索引
    //printf("%d,%d,%d\n",i,left,right);
    // 比较左孩子和父结点大小,再用其中较大者与右孩子比较 
    if(left <= heapsize-1 && a[i] < a[left])
    {
        largest = left;
    }
    else
    {
        largest = i;
    }
    if(right <= heapsize-1 && a[largest] < a[right])
    {
        largest = right;
    }
    // 如果最大者不是父结点,将父结点与最大者进行交换
    if(largest != i)
    {
        temp = a[i];
        a[i] = a[largest];
        a[largest] = temp;
        // 交换之后有可能违反最大堆性质,递归调用维护性质
        max_heapify(a, largest, heapsize);
    }
}

// 构建最大堆,通过遍历节点,实现根结点是堆数据中的最大值
void build_max_heap(int a[], int heapsize)
{
    int i, count = 0;
    // 从后到前,对结点进行遍历维护
    for(i=(int)(heapsize/2) - 1; i>=0; i--)
    {
        max_heapify(a, i, heapsize-count);
        count = count + 1;
    } 
}

// 交换函数
void swap(int a[], int i, int j)
{
    int temp;
    temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

// 构建最大堆之后,根结点处有最大的数,将最大值与最后的数交换取出,再对剩余的 len-1 数据继续重复此操作
void heap_sort(int a[], int heapsize)
{
    int i;
    build_max_heap(a, heapsize);
    for(i = heapsize - 1; i>=1; i--)
    {
        swap(a, 0, i);    // 交换根结点和最后一个数
        max_heapify(a, 0, i);
    }
}

int main(void)
{
    int a[10] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
    int i, heapsize;
    heapsize = sizeof(a)/sizeof(a[0]);
    //printf("%d,%d\n",sizeof(a),sizeof(a[0]));
    //printf("%d\n", heapsize);
    heap_sort(a, heapsize);
    //build_max_heap(a);
    for(i=0; i<10; i++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

参考《算法导论》

上一篇下一篇

猜你喜欢

热点阅读