《算法导论》读书笔记--堆排序

预备知识:

堆通常被看做一个近似完全的二叉树,使用数组A[1...N]表示堆,数组中一个元素代表堆上一个结点,堆存在以下性质:

根节点:A[1]

父结点:Parent[i] = i/2

左子节点:Left[i] = 2i

右子节点:Right[i] = 2i + 1

数组长度为:A.length

数组中有效数据长度为:A.heap-size

堆分为最大堆和最小堆,在最大堆中 Parent[i] >= A[i],在最小堆中 Parent[i]  <= A[i]


维护堆的性质(MAX-HEAPIFY):调节父结点与子结点位置,使他们满足最大堆的大小关系。将A[i]的值在最大堆中“逐级下降”,从而使以下标i为根结点的子树重新遵循最大堆的性质。

MAX-HEAPIFY(A,i)
l = Left[i]
r = Right[i]
if l <= A.heap-size and A[l] > A[i]
    lagest = l
else
    lagest = i
if r <= A.heap-size and A[r] > A[lagest]
    lagest = r
if i != lagest //当根结点不是最大值时
    exchage A[i] with A[lagest]
    MAX-HEAPIFY(A,lagest)//交换位置后,以该结点为根的子树可能违法最大堆的性质,所以需要递归调用

时间复杂度为:T(n) <= T(2/3n)+O(1) 根据主定理公式可以计算出 时间复杂度为O(lgn)


建堆(BUILD-MAX-HEAP):将无序的数组转换为最大堆。

BUILD-MAX-HEAP(A)
A.heap-size = A.length 
for i = [A.heap-size/2] downto 1 //此处i的值为A.heap-size/2向下取整的值,因为A[A.heap/2+1...A.heap-size]为叶子结点,没有子结点,所以只需考虑前半部分的值
    MAX-HEAPIFY(A,i)
时间复杂度为 O(n)


堆排序算法(HEAPSORT):因为建堆后,数组中的数据并不是有序的,但最大值一定位于根结点A[1],根据此性质,可以进行排序

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 //有效长度减1,表示该元素已经归位
        MAX-HEAPIFY(A,1) //因为将原堆末尾元素提到了根结点,所以需要对根结点重新执行MAX-HEAPIFY维护堆的性质。
时间复杂度为O(nlogn)

Demo:

#include 
#include 
using namespace std;

#define LENGTH 10

int heap_size = 0;

void swap(int *a,int *b)
{
	int tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

void max_headpify(int *A,int i)//维护堆的性质,下沉元素
{
	int lagest;
	int l = i*2;
	int r = i*2+1;

	if((l <= heap_size) && (A[l] > A[i]))
		lagest = l;
	else 
		lagest = i;
	if((r <= heap_size) && (A[r] > A[lagest]))
		lagest = r;

	if(lagest != i)
	{
		swap(&A[i],&A[lagest]);
		max_headpify(A,lagest);
	}
}

void build_max_heap(int *A)//构建堆
{
	heap_size = LENGTH;
	for(int i = LENGTH/2;i >= 1;i--)
		max_headpify(A,i);
}

void heapsort(int *A)//堆排序
{
	build_max_heap(A);
	for(int i = LENGTH;i >= 2;i--)
	{
 		swap(&A[1],&A[i]);
		heap_size--;
		max_headpify(A,1);
	}
}

int main()
{
	int A[LENGTH+1];
	for(int i = 1;i <= LENGTH;i++)
	{
		cin>>A[i];
	}

	heapsort(A);

	for(int i = 1;i <= LENGTH;i++)
	{
		printf("%d\n",A[i]);
	}
	system("pause");
	return 0;
}



你可能感兴趣的:(算法)