您的位置:首页 > 其它

堆排序解析

2016-02-01 10:39 309 查看
首先要了解堆的性质,我这里简答总结一下(这里说的是小堆):

1、堆是一棵完全二叉树

2、对于大堆中的任何一个非叶子节点,节点的值必须小于左右孩子节点值。


由此可知,对于小堆而言,根节点就是最小值了,那么我们每次拿走根节点,拿走的顺序就是递增序列的。

排序的元素在数组中,而堆也是一棵完全二叉树,所以直接用数组表示二叉树。

对于完全二叉树中的K节点,其满足一下性质:

1、K节点的父节点为( k - 1 ) / 2

2、K节点的左子节点为2K + 1

3、K节点的右子节点为2K + 2


所以堆排序的步骤如下:

1、填充二叉树元素,由于我们直接用源数据表示二叉树,所以这里不用写了。

2、由堆的性质可知,任何叶子节点都是满足堆的性质的,所以找到第一个非叶子节点的节点,从该节点开始,调整所有节点,让他们满足堆的性质

3、移走堆的根节点,得到当前的最大值。

4、将最后一个节点移至根节点,此时除了根节点外其余节点都是满足要求的,重新调整堆,重复第3步。

[cpp] view
plaincopy

void heapAdjust(int a[], int n, int index) //建立的是小根堆

{

int l = 2 * index + 1; //左子节点索引

int r = 2 * index + 2; //右子节点索引

if ( r >= n && l >= n ) return; //该节点没有子节点

int left = 0x7FFFFFFF, right = 0x7FFFFFFF;

if ( l < n ) left = a[l];

if ( r < n ) right = a[r];

if (a[index] <= left && a[index] <= right ) return; //节点值小于左右子节点值,符合条件,直接返回

if (left < right) //节点与较小的子节点交换

{

int t = a[index];

a[index] = left;

a[l] = t;

heapAdjust(a, n, l);

}

else

{

int t = a[index];

a[index] = right;

a[r] = t;

heapAdjust(a, n, r);

}

}

void heapSort(int a[], int n)

{

for ( int i = (n - 1) / 2; i >= 0; --i) //最后一个非叶子节点,也就是左后一个叶子节点的父节点

{

heapAdjust(a, n, i);

}

while (n > 0)

{

printf("%d ", a[0]);

int t = a[0]; //移走最小值

a[0] = a[n-1];

a[n-1] = t;

n--; //堆变小

heapAdjust(a, n, 0);

}

}

int main()

{

int a[] = {3, 5, 1, 4, 7, 3, 2, 5, 3, 8};

for ( int i = 0; i < 10; ++i)

{

printf("%d ", a[i]);

}

printf("\n");

heapSort(a, 10);

printf("\nAfter sort:\n");

for ( int i = 0; i < 10; ++i)

{

printf("%d ", a[i]);

}

printf("\n");

}

由于建立的是小根堆,所以最后得到是将序列。



最后附一个堆排的动画

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: