您的位置:首页 > 其它

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

2016-01-08 16:35 176 查看
预备知识:

堆通常被看做一个近似完全的二叉树,使用数组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 <iostream>
#include <stdio.h>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: