[算法导论]优先队列(基于堆排序)

 
#include<stdio.h>
#include<iostream>

using namespace std;
#define Length 10

void MaxHeapify(int num[], int i, int len);//堆调整 
void BuildHeap(int num[], int len);//建立初始最大队 
int Heapsort(int num[], int len);//堆排序 
int HeapExtractMax(int num[], int len);//优先队列 利用堆排序 
void HeapIncreaseKey(int num[], int i, int key);//增大堆中指定位置的关键字的值  
void Output(int num[], int len);

int main ()
{
	int num[Length] = {12, 2, 34, 56, 26, 8, 31, 6, 20, 3};
	BuildHeap(num, Length);
	cout << "初始堆:" <<endl; 
	Output(num, Length);
	
	cout << endl << "将指定位置的关键字的值增加并调整成新堆: " << endl; 
	HeapIncreaseKey(num, 7, 99);
	Output(num, Length);
	
	int key = HeapExtractMax(num, Length);//与BuildHeap配套使用 
	printf("\n优先队列(最大值): %d\n", key);
	
	cout << "\n将最大值输出并调整成新堆: "<< endl; 
	Output(num, Length - 1);

} 

//因为某未知的关键字的值增大 因此可能会改变最大堆的性质 因此需要对堆进行调整 
void HeapIncreaseKey(int num[], int i, int key)//见图IncreaseKey 
{
	int t;
	if (key < num[i])
	{
		cout << "new key is smaller than current key";
		return;
	}
	
	num[i] = key;//将指定位置的关键字的值进行增加 
	
	while(i > 0 && num[i / 2] < num[i]) //i/2代表的是i的双亲结点 因为本函数是进行关键只增加的操作 因此只需要逐级向上比较 
	{//最好是i>0因为i=0时以下操作都是对0自身的操作 无意义 
		t = num[i];
		num[i] = num[i / 2];
		num[i / 2] = t;
		i /= 2;
	}	
}
	
int HeapExtractMax(int num[], int len)
{
	if(len < 1)
	printf("error!!");
	
	int max = num[0];
	int t = num[0];
	num[0] = num[len - 1];
	num[len - 1] = t;
	len--;
	MaxHeapify(num, 0, len - 1);
	return max;	
}
//堆排序的关键是一定要搞清楚len 在每个函数中的不同值 是长度还是下标 
int Heapsort(int num[], int len)//此处的len代表的是实际长度 
{
	int t;
	for(int i = len - 1; i >= 1; i--)//在堆排序的过程中0位存储的是最大值 因此每次进行排序的时候都将0位的元素和最后一位进行交换 
	{
		t = num[i];
		num[i] = num[0];
		num[0] = t;
		len--;//每执行一次就可以得到高位的一个元素 此时len应该-1 即每次执行的长度是递减的 
		MaxHeapify(num, 0, len - 1); //一定是len - 1!!! 因为在MaxHeapify中 第三个参数代表的是数组的角标  比实际长度小1 
	}
}
//BuildHeap只是用一次 即构建初始堆 因为之后的对调整函数需要在初始堆的基础上进行操作 
void BuildHeap(int num[], int len)//建堆  len是长度  利用给定的数组num 
{
	for(int i = len/2; i >= 0; i--)//i的初始值是 len/2向下取整  利用的是二叉树中双亲结点与子节点之间的下标关系 
	{
		MaxHeapify(num, i, len - 1);//在MaxHeapify中 
	}//for循环结束后 就构建好了初始堆 
}

//这个函数的作用是调整堆 
void MaxHeapify(int num[], int i, int len)//见图Heapsort 
{
	int left = 2 * i;//left是i的左孩子的下标  由二叉树的性质可以知道 
	int right = 2 * i + 1;
	int largest, t;
	
	//下面几行语句的作用是在i以及i的左右孩子中找到最大值 并将其位置保存在largest中 
	if(left <= len && num[left] > num[i])
	largest = left;
	else
	largest = i;
	
	if(right <= len && num[right] > num[largest])
	largest = right;
	
	if(largest != i)//满足if条件则说明 i的其中一个子节点大于它 并将出现交换的操作 
	{
		t = num[i];
		num[i] = num[largest];
		num[largest] = t;
		MaxHeapify(num, largest, len);//交换之后需要重新判断原i的值是否比原largest的全部子节点的值都大 
	}
} 

void Output(int num[], int len)
{
    for(int i=0; i<len; i++)
    {
        printf("%d  ", num[i]);
    }
    cout << endl;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值