首先要了解堆的性质,我这里简答总结一下(这里说的是小堆):
1、堆是一棵完全二叉树
2、对于大堆中的任何一个非叶子节点,节点的值必须小于左右孩子节点值。
由此可知,对于小堆而言,根节点就是最小值了,那么我们每次拿走根节点,拿走的顺序就是递增序列的。
排序的元素在数组中,而堆也是一棵完全二叉树,所以直接用数组表示二叉树。
对于完全二叉树中的K节点,其满足一下性质:
1、K节点的父节点为( k - 1 ) / 2
2、K节点的左子节点为2K + 1
3、K节点的右子节点为2K + 2
所以堆排序的步骤如下:
1、填充二叉树元素,由于我们直接用源数据表示二叉树,所以这里不用写了。
2、由堆的性质可知,任何叶子节点都是满足堆的性质的,所以找到第一个非叶子节点的节点,从该节点开始,调整所有节点,让他们满足堆的性质
3、移走堆的根节点,得到当前的最大值。
4、将最后一个节点移至根节点,此时除了根节点外其余节点都是满足要求的,重新调整堆,重复第3步。
- 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");
- }
由于建立的是小根堆,所以最后得到是将序列。
最后附一个堆排的动画