堆排序

算法导论之堆排序

1:保持堆的性质

MAX-HEAPIFY(A, i)
 1 l  LEFT(i)
 2 r  RIGHT(i)
 3 if l  heap-size[A] and A[l] > A[i]
 4    then largest  l
 5    else largest  i
 6 if r  heap-size[A] and A[r] > A[largest]
 7    then largest  r
 8 if largest  i
 9    then exchange A[i]  A[largest]
10         MAX-HEAPIFY(A, largest)

如图所示:


Figure  The action of MAX-HEAPIFY(A, 2), where heap-size[A] = 10. (a) The initial configuration, with A[2] at node i = 2 violating the max-heap property since it is not larger than both children. The max-heap property is restored for node 2 in (b) by exchanging A[2] with A[4], which destroys the max-heap property for node 4. The recursive call MAX-HEAPIFY(A, 4) now has i = 4. After swapping A[4] with A[9], as shown in (c), node 4 is fixed up, and the recursive call MAX-HEAPIFY(A, 9) yields no further change to the data structure.


2:构建堆

BUILD-MAX-HEAP(A)
1  heap-size[A]  length[A]
2  for i  length[A]/2 downto 1
3       do MAX-HEAPIFY(A, i)

图示:


Figure 6.3: The operation of BUILD-MAX-HEAP, showing the data structure before the call to MAX-HEAPIFY in line 3 of BUILD-MAX-HEAP. (a) A 10-element input array A and the binary tree it represents. The figure shows that the loop index i refers to node 5 before the call MAX-HEAPIFY(A, i). (b) The data structure that results. The loop index i for the next iteration refers to node 4. (c)-(e) Subsequent iterations of the for loop in BUILD-MAX-HEAP. Observe that whenever MAX-HEAPIFY is called on a node, the two subtrees of that node are both max-heaps. (f) The max-heap after BUILD-MAX-HEAP finishes.

3:堆排序

HEAPSORT(A)
1 BUILD-MAX-HEAP(A)
2 for i  length[A] downto 2
3    do exchange A[1]  A[i]
4       heap-size[A]  heap-size[A] - 1
5       MAX-HEAPIFY(A, 1)

图示:


Figure 6.4: The operation of HEAPSORT. (a) The max-heap data structure just after it has been built by BUILD-MAX-HEAP. (b)-(j) The max-heap just after each call of MAX-HEAPIFY in line 5. The value of i at that time is shown. Only lightly shaded nodes remain in the heap. (k) The resulting sorted array A.

The HEAPSORT procedure takes time O(n lg n), since the call to BUILD-MAX-HEAP takes time O(n) and each of the n - 1 calls to MAX-HEAPIFY takes time O(lg n).

代码实现:

#include <iostream>
using namespace std;
#define  M 11
void swap(int *data,int i,int j)
{
	int m = data[i];
	data[i] = data[j];
	data[j] = m;
}
// 堆化,保持堆的性质
// MaxHeapify让a[i]在最大堆中"下降",
// 使以i为根的子树成为最大堆
void MaxHeapfiy(int *data,int i,int length)
{
	int lchild = 2*i;
	int rchild = 2*i+1;
	int largest = i;
	if (lchild <=length&&data[i] < data[lchild])largest = lchild;
	if(rchild <= length&&data[largest] < data[rchild])largest = rchild;
	if (largest!=i)
	{
		swap(data,i,largest);
		MaxHeapfiy(data,largest,length);
	}
}
// 建堆
// 自底而上地调用MaxHeapify来将一个数组a[1..size]变成一个最大堆
//
void BuildHeap(int *data,int length)
{
	for (int i = (length)/2;i>=1;--i)
	{
		MaxHeapfiy(data,i,length);
	}
}
// 堆排序
// 初始调用BuildMaxHeap将a[1..size]变成最大堆
// 因为数组最大元素在a[1],则可以通过将a[1]与a[size]互换达到正确位置
// 现在新的根元素破坏了最大堆的性质,所以调用MaxHeapify调整,
// 使a[1..size-1]成为最大堆,a[1]又是a[1..size-1]中的最大元素,
// 将a[1]与a[size-1]互换达到正确位置。
// 反复调用Heapify,使整个数组成从小到大排序。
// 注意: 交换只是破坏了以a[1]为根的二叉树最大堆性质,它的左右子二叉树还是具备最大堆性质。
//        这也是为何在BuildMaxHeap时需要遍历size/2到1的结点才能构成最大堆,而这里只需要堆化a[1]即可。
void HeapSort(int *data,int size)
{
	BuildHeap(data,size);
	int len = size;
	for (int i = len; i >=2; --i)
	{
		int elemt = data[1];
		data[1] = data[len];
		data[len] = elemt;
		len--;
		MaxHeapfiy(data,1,len);
	}
}
void PrintArray(int *data)
{
	for (int i = 1; i < M; i++)
	{
		cout<<"a["<<i<<"]:"<<data[i]<<endl;
	}
}

int main()
{
	int a[M];
	a[0] = 0;
	for (int i = 1; i < M;i++)
	{
		a[i] = rand()%100;
		cout<<"a["<<i<<"]:"<<a[i]<<endl;
	}
	BuildHeap(a,20);
	PrintArray(a);
	cout<<endl<<"----------"<<endl;
	HeapSort(a,20);
	PrintArray(a);
	system("pause");
	return 0;
}


编程珠玑 代码实现:

#include <iostream>
using namespace std;
#define  M 11
void swap(int *data,int i,int j)
{
	int m = data[i];
	data[i] = data[j];
	data[j] = m;
}
void PrintArray(int *data)
{
	for (int i = 1; i < M; i++)
	{
		cout<<"a["<<i<<"]:"<<data[i]<<endl;
	}
}
//siftup比较好理解,将每一个元素都与自己的父亲比较,如果自己的值小于父亲的值,就互换,直到到堆顶,或父亲的值小于自己的值为止。  
void siftup(int *data,int n)
{
	int p;
	int i = n;
	while(1)
	{
		if(i == 1)break;
		p = i/2;
		if(data[p] < data[i])break;
		swap(data,p,i);
		i = p;
	}
}
//当data[1..n]是一个堆时,給data[1]重新分配一个新的值得到heap(2,n),然后用函数siftdown使得heap(1,n)为真,
//该函数将x[1]向下筛选,直到它没有子节点或者小于等于它的子节点
void siftdown(int *data,int n)
{
	int i = 1;
	int lc = 0;
	int rc = 0;
	int c_smaller = 0;
	while(1)
	{
		lc = 2*i;
		rc = lc+1;
		c_smaller = lc;
		if (lc > n)break;
		if(rc <= n&&data[rc]<data[lc])c_smaller = rc;

		if(data[i] <= data[c_smaller])break;
		swap(data,c_smaller,i);
		i = c_smaller;
	}
}
int main()
{
	int a[M];
	a[0] = 0;
	for (int i = 1; i < M;i++)
	{
		a[i] = rand()%100;
		cout<<"a["<<i<<"]:"<<a[i]<<endl;
	}
	//堆排序
	for (int i = 2; i <= M -1; i++)//建立小堆
	{
		siftup(a,i);
	}
	PrintArray(a);
	for(int i = M - 1; i >=2;i--)//堆顶与最后一个元素互换,1到i为堆,i到n为已排序元素
	{
		swap(a,1,i);
		siftdown(a,i - 1);
	}
	PrintArray(a);
	system("pause");
	return 0;
}




posted @ 2012-04-09 14:23  foreverlearn  阅读(166)  评论(0编辑  收藏  举报