Fork me on GitHub

堆的操作集

什么是堆

  • 优先队列( Priority Queue):特殊的“队列” ,取出元素的顺序是
    依照元素的优先权(关键字) 大小,而不是元素进入队列的先后顺序

问题:如何组织优先队列?
 一般的数组、链表?
 有序的数组或者链表?
 二叉搜索树? AVL树

  • 产生了堆这种数据结构,知道基本操作集

  • 增查的操作方式,创建的方法

测试代码

/*!
 * \file 堆的操作集.cpp
 *
 * \author ranjiewen
 * \date 2017/04/06 23:25
 *
 * 
 */

#include <stdio.h>
#include <stdlib.h>

typedef struct HNode *Heap;  //堆的类型定义
typedef int Elementype;

struct HNode 
{
	Elementype *Data; //存储元素的数组  //堆是完全二叉树,用数组存储利用率高
	int size; //堆中当前元素的个数
	int capacity; //堆的最大容量
};

typedef Heap MaxHeap; //最大堆
typedef Heap MinHeap; //最小堆

#define MAXDATA 1000  //该值应根据情况定义为大于堆中所有可能元素的值

MaxHeap CreateHeap(int MaxSize)
{
	//创建容量为MaxSize的空的最大堆
	MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));
	H->Data = (Elementype*)malloc((MaxSize+1)*sizeof(Elementype));
	H->size = 0;
	H->capacity = MaxSize;
	H->Data[0] = MAXDATA; //定义“哨兵”为大于堆中所有可能元素的值
	return H;
}

int IsFull(MaxHeap H)
{
	return H->size == H->capacity;
}

//bool
int Insert(MaxHeap H, Elementype x)
{
	//将元素x插入最大堆H,其中H->Data[0]已经定义为哨兵
	int i;
	if (IsFull(H))
	{
		printf("最大堆已满!");
		return false;
	}
	i = ++H->size; //i指向插入后堆中的最后一个元素的位置
	//先直接到插入到数组最后的元素,然后在调整堆
	for (; H->Data[i / 2] < x;i/=2)  //父节点比它小
	{
		H->Data[i] = H->Data[i/2]; // 和父节点交换
	}
	H->Data[i] = x; //找到插入位置,插入

	return 1;
}

#define  ERROR -1  //错误标识,定义为堆中不可能出现的元素值

bool IsEmpty(MaxHeap H)
{
	return H->size == 0;
}

Elementype DeleteMax(MaxHeap H)
{
	//从最大堆H中取出键值为最大的元素,并删除一个结点
	int Parent, Child;
	Elementype MaxItem, x;

	if (IsEmpty(H))
	{
		printf("最大堆已为空");
		return ERROR;
	}
	MaxItem = H->Data[1]; //取出根节点存放的最大值
	
	//用最大堆中最后一个元素从根节点开始向上过滤下层结点
	x = H->Data[H->size--];  //注意当前堆的规模要减小
	for (Parent = 1; Parent * 2 <= H->size;Parent=Child)
	{
		Child = Parent * 2;
		if ((Child!=H->size) && (H->Data[Child]<H->Data[Child+1]) )  //Child指向左右子节点中较大者  //注意没有右孩子的情况
		{
			Child++; 
		}
		if (x>=H->Data[Child])
		{
			break;   //找到合适的位置
		}
		else   /* 下滤X */
		{
			H->Data[Parent] = H->Data[Child];
		}
	}
	H->Data[Parent] = x;

	return MaxItem;
}

/*------------建造最大堆----------------------*/

void PrecDown(MaxHeap H, int p)
{
	//下滤:将H中以H->Data[p]为根的子堆调整为最大堆
	int Parent, Child;
	Elementype x;

	x = H->Data[p]; //取出根节点存放的值
	for (Parent = p; Parent * 2 <= H->size;Parent=Child)
	{
		Child = Parent * 2;
		if ((Child!=H->size)&&(H->Data[Child]<H->Data[Child+1]))
		{
			Child++; //Child指向左右子节点的较大者
		}
		if (x>=H->Data[Child])
		{
			break;
		}
		else   /* 下滤X */
		{
			H->Data[Parent] = H->Data[Child];
		}
	}
	H->Data[Parent] = x;
}

void BuildHeap(MaxHeap H)
{
	//调整H->Data[]中的元素,是满足最大堆的有序性
    //这里假设所有H->size个元素已经存在H->Data[]中
	int i;
	//从最后一个结点的父节点开始,到根结点
	for (i = H->size / 2; i > 0;i--)
	{
		PrecDown(H, i);
	}
}


int main()
{
	MaxHeap H;
	H = CreateHeap(10);
	for (int i = 0; i < 10;i++)
	{
		Insert(H, i + 10);
	}
	for (int i = 0; i < H->size;i++)
	{
		printf("%d ", H->Data[i + 1]);
	}
	printf("\n");

	for (int i = 0; i < H->size; i++)
	{
		H->Data[i + 1] = i + 10;
	}
	BuildHeap(H);
	for (int i = 0; i < H->size; i++)
	{
		printf("%d ", H->Data[i + 1]);
	}
	printf("\n");
	return 0;
}


posted @ 2017-04-08 01:04  ranjiewen  阅读(455)  评论(0编辑  收藏  举报