[算法导论]堆排序

1: 如图所示,(二叉)堆是一个 数组,它可以被看成一个近似的 完全二叉树
表示堆的数组A有两个属性:
A.length 给出数组元素个数
A.heap-size 表示有多少个堆元素存储在该数组中
也就是说 A[1..length]可能都存放有数据,但只有A[1..A.heap-size]中存放的是堆的有效元素。

这里 0 <= A.heap-size <= A.length




2. 树的根节点是A[i],这样给定一个结点的下标i,我们很容易计算得到它的父结点、左孩子、右孩子的下标
	PARENT(i)
		return i/2;
	LEFT(i)
		return 2*i;
	RIGHT(i)
		return 2*i+1;
(可用 宏定义实现)


3. 二叉堆有两种形式: 最大堆和最小堆
最大堆: 除根结点外,所有的结点 i 都要满足:
A[PARENT[i]] >= A[i]
最小堆: 除根结点外,所有结点 i 都要满足:
A[PARENT(i)] <= A[i]

4. 维护堆的性质( 以最大堆为例
MAX_HEAPIFY 是用于维护最大堆性质的重要过程。它输入为一个数组A和一个下标i。

在调用 MAX_HEAPIFY 的时候,我们假定根结点为 LEFT(i) 和 RIGHT(i) 的二叉树都是最大堆(这个是必须的假设。也就是说,在调整堆的某个结点 i 时,

必须保证 结点 i 的孩子结点都满足最大堆性质)

	
	MAX_HEAPIFY(A,i)
		l = LEFT(i);	//获得左孩子结点
		r = RIGHT(A,i);  //获得右孩子结点
		if l<=A.heap-size and A[l]>A[i]    // 如果做孩子结点是堆元素,并且左孩子结点的关键值大于父结点的关键值
			largest = l;                   //记录结点关键字最大的下标
		else	largest = i;
		if r<=A.heap-size and A[r] > A[largest]
			largest = r;
		if largest ≠ i
			exchange A[i] width A[largest]
			MAX_HEAPIFY(A,largest)       // 调整堆



5.  建堆
我们用自顶向上的方法利用过程 MAX_HEAPIFY 把一个大小为 A.length 的数组 A[1..n] 装换为最大堆
首先,从完全二叉树的性质可知, 子数组[n/2 + 1, ...n] 都是树的叶结点。每个叶结点可以看成是一个
堆元素,由于它们没有孩子结点,它们自然满足最大堆的性质。
所以,需要我们处理的是 子数组[1...n/2] 这些非叶结点。

算法如下:
	BUILD_MAX_HEAP(A)
			A.heap-size = A.length           
			for i = [A.length/2] downto 1    
				MAX_HEAPIFY(A,i);



6.  堆排序算法
初始时候,堆排序算法利用 BUILD_MAX_HEAP 将输入数组 A[1...n]建成最大堆,其中 n  = A.length.
因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的
位置。这时候,如果我们从堆中去掉结点n(这操作可以通过减少A.heap-size的值来实现),剩余的
结点中,原来的根的孩子仍然是最大堆,而新结点可能会违背最大堆的性质。为了维护最大堆的性质,
我们要做的是调用 MAX_HEAPIFY(A,1),从而在A[1...n-1] 上构造一个新的最大堆。
堆排序会 不断重复这个过程,直到堆的大小从 n-1 降到2
	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;
			MAX_HEAPIFY(A,1)




优先队列
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个相关的值,称为关键字。
一个最大优先队列支持一下操作:
INSERT(S,x): 把元素X插入集合S中。这一操作等价于S=SU{X}。
MAXIMUM(S) : 返回S中具有最大关键字的元素
EXTRACT_MAX(S): 去掉并返回S中的具有最大关键字的元素。
INCREASE_KEY(S,x,k): 将元素X的关键字值增加到k,这里假设k的值不小于x的原关键字



EXTRACT_MAX(S)
		if A.heap-size < 1
			error "heap underflow"
		max = A[1]
		A[1] = A[A.heap-size]
		A.heap-size = A.heap-size - 1
		MAX_HEAPIFY(A,1)	
		return max	
			
			
	INCREASE_KEY(S,x,k)
		if key < A[i]
			error "new key is smaller than current key"
		A[i] = key
		while i > 1 and A[PARENT(i)] < A[i]
			exchange A[i] with A[PARENT(i)]
			i = PARENT(i);
			
			
	INSERT(S,x)
		A.heap-size = A.heap-size + 1;
		A[A.heap-size] = -无穷
		INCREASE_KEY(S,A.heap-size,x)



代码实现(不包括)

#include "iostream"

#define PARENT(i) (i/2)
#define LEFT(i) (2*i)
#define RIGHT(i) (2*i+1)
#define Heapswap(a,b) (a = a+b, b=a-b, a= a-b)

struct Heap {
	int A[256] = {0}; // 0位不要,下标从1开始
	unsigned length = 0;   // 数组有效位数
	unsigned heapSize = 0;  // 堆元素 
	unsigned const MaxSize = 256;  //数组容量
};

void InitialHeap(Heap& hp, int A[], int Arrlength, int HeapLength);//初始化堆
void Print(Heap hp); // 打印 堆元素
void MaxHeapify( Heap &hp, int i); // 维护堆的性质
void BuildMaxHeap(Heap &hp); // 建堆
void HeapSort(Heap &hp);  // 堆排序算法

int main(void)
{

	#if 1  //测试
Heap hp;
	int A[] = {9,10,18,1,12,6,9,11,13,2};
	//初始化
	InitialHeap(hp, A, 10, 0);
	//建堆
	BuildMaxHeap(hp);
	//输出数据
	Print(hp);
	std::cout << std::endl;



	//堆排序
	HeapSort(hp);
	for (size_t i = 1; i <= hp.length; i++)
	{
		std::cout << hp.A[i] << "  ";
	}
	std::cout << std::endl;

	system("pause");  
#endif
	return 0;
}

void InitialHeap(Heap & hp, int A[], int Arrlength, int HeapLength)
{
	for (int i = 0; i < Arrlength; i++)
		hp.A[i+1] = A[i];
	hp.length = Arrlength;
	hp.heapSize = HeapLength;
}

void Print(Heap hp)
{
	for (size_t i = 1; i <= hp.heapSize; i++)
	{
		std::cout << hp.A[i] << "  ";
	}
}

void MaxHeapify(Heap &hp, int i)
{
	int left = LEFT(i);
	int right = RIGHT(i);
	int largest = -1;
	// 是堆元素并且是孩子结点大于父子结点
	if (left <= hp.heapSize && hp.A[left] > hp.A[i])
		largest = left;
	else
		largest = i;
	if (right <= hp.heapSize && hp.A[right] > hp.A[largest])
		largest = right;

	if (largest != i)
	{
		Heapswap(hp.A[largest], hp.A[i]);
		
		MaxHeapify(hp, largest);
	}
}

void BuildMaxHeap(Heap &hp)
{
	hp.heapSize = hp.length;
	for (int i = hp.length / 2; i >= 1; i--)
		MaxHeapify(hp, i);
}

void HeapSort(Heap & hp)
{
	BuildMaxHeap(hp); //建堆
	for (int i = hp.length; i >= 2; i--)
	{
		Heapswap(hp.A[1], hp.A[i]);
		hp.heapSize = hp.heapSize - 1;
		MaxHeapify(hp, 1);
	}

}











  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值