最小堆的插入、删除和创建的C语言实现

堆是一种特殊的“队列”,它取出元素的顺序是依照元素的优先级大小,而不是元素进入队列的先后顺序。堆具有两个特性,1.结构性:它是能用数组表示的完全二叉树。2.堆序性:任一结点的关键字是其子树所有结点的最大值(最大堆)或最小值(最小堆),即任意子树也应该是个堆。

根据最小堆的结构特性,本文使用含有哨兵元素的数组实现了最小堆的创建、插入和删除。

数据类型定义和函数声明

#include
#include

#define MinData -100//哨兵元素的值
typedef struct HeapStruct{
	int *p;
	int size;
	int capacity;
} *MinHeap;

MinHeap Init_MinHeap(int MaxSize);
int IsFull(MinHeap H);
int IsEmpty(MinHeap H);
void Insert(MinHeap H, int data);
int Delete(MinHeap H);
void BuildMinHeap(MinHeap H, int N);
void PrintValue(MinHeap H);

程序中用到的功能函数

int IsFull(MinHeap H)
{
	return (H->size == H->capacity) ? 1 : 0;
}

int IsEmpty(MinHeap H)
{
	return (H->size == 0) ? 1 : 0;
}

void PrintValue(MinHeap H)
{
	int i;
	printf("最小堆中的元素依次为:");
	for (i = 1; i <= H->size; i++)
		printf("%d ", H->p[i]);
	printf("\n");
}

最小堆的初始化

该函数给最小堆分配了内存空间并完成初始化操作,此时最小堆中元素为空。

MinHeap Init_MinHeap(int MaxSize)
{
	MinHeap H = (MinHeap)malloc(sizeof(HeapStruct));
	H->p = (int*)malloc((MaxSize + 1) * sizeof(int));
	H->p[0] = MinData;
	H->size = 0;
	H->capacity = MaxSize;
	return H;
}

在最小堆中插入元素

插入元素的关键是把要插入的元素放在最小堆的合适位置中。所谓合适即不破坏最小堆的结构性和堆序性。

为了将一个元素data插入到堆中,在遵守堆的结构性特点(完全二叉树)基础上,在下一个空闲位置创建一个空穴。如果元素data可以放在该空穴中而并不破坏堆的序,则完成插入。否则,把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上移动一层。继续该过程知道元素data能放入空穴中。因为空穴在逐渐往树的上方移动,所以把这种策略成为“上滤”。

void Insert(MinHeap H, int data)
{
	int i;
	if (IsFull(H))
	{
		printf("最小堆已满,无法插入元素");
		return;
	}
	for (i = ++H->size; data < H->p[i / 2]; i /= 2)
		H->p[i] = H->p[i / 2];
	H->p[i] = data;
}

删除最小堆中的最小元素

删除元素的关键是把堆中最后一个元素移动到最小堆中的合适位置。所谓合适即不破坏最小堆的结构性和堆序性。

删除元素以类似于插入的方式处理。找到最小元很容易(第一个元素),困难的部分是删除后的调整。当删除一个最小元时,在根节点处产生一个空穴。由于现在堆里少了一个元素,因为堆中最后一个元素lastvalue必须移动到该堆的某个地方。通常我们将空穴的两个儿子中较小者移入空穴,这样就把空穴向下退了一层。重复该步骤知道lastvalue可以放在空穴中。通常把这种策略成为“下滤”。

int Delete(MinHeap H)
{
	int minvalue , lastvalue, child, parent;
	if (IsEmpty(H))
	{
		printf("最小堆已满,无法删除元素");
		return -999;
	}

	minvalue = H->p[1];
	lastvalue = H->p[H->size--];
	for (parent = 1; 2 * parent <= H->size; parent = child)
	{
		child = 2 * parent;/*默认左结点的元素值更小*/
		if (child != H->size && H->p[child + 1] < H->p[child])/*若右节点的元素值更小,则调整child*/
			child++;
		if (lastvalue < H->p[child])
			break;
		else
			H->p[parent] = H->p[child];
	}
	H->p[parent] = lastvalue;
	return minvalue;
}

创建最小堆

在创建最小堆时,可以 : 通过插入操作Insert函数,将N 个元素一个个相继插入到一个初始为空的堆中去 ,但其时间代价最大为O(NlogN)。

也可以在线性复杂度下建立最小堆,基本步骤为:1. 将N个元素按输入顺序存入,先满足完全二叉树的结构特性。2.调整各节点位置,以满足最大堆的堆序性。这样创建最小堆时的时间代价为O(N)。在调整节点位置时,只需对从第N/2个节点到第一个节点依次应用“下滤”策略即可,其实也就是进行了N/2次的近似删除操作。

void BuildMinHeap(MinHeap H, int N)
{
	int i, num, parent, child, root, lastvalue;
	if (N > H->capacity)
	{
		printf("要创建的元素个数超过堆的最大容量,创建失败");
		return;
	}
	for (i = 1; i <= N; i++)
	{
		printf("请输入要插入的元素值:");
		scanf_s("%d", &num);
		H->p[i] = num;
	}
	H->size = N;

	root = N / 2;/*从第N/2个结点到第1个结点依次进行下滤 近似N/2次删除操作*/
	while (root)
	{
		lastvalue = H->p[root];
		for (parent = root; 2 * parent <= H->size; parent = child)
		{
			child = 2 * parent;/*默认左结点的元素值更小*/
			if (child != H->size && H->p[child + 1] < H->p[child])/*右结点元素值更小*/
				child++;
			if (lastvalue < H->p[child])
				break;
			else
				H->p[parent] = H->p[child];
		}
		H->p[parent] = lastvalue;
		--root;
	}
}

主程序

测试序列:150 80 40 30 10 70 110 100 20 90 60 50 120 140 130

正确结果为:10 20 40 30 60 50 110 100 150 90 80 70 120 140 130

void main()
{
	int num;
	MinHeap H;
	H = Init_MinHeap(100);
	BuildMinHeap(H, 15);
	PrintValue(H);

	printf("请输入你要插入的数据:");
	scanf_s("%d", &num);
	Insert(H, num);
	PrintValue(H);
	printf("请输入你要插入的数据:");
	scanf_s("%d", &num);
	Insert(H, num);
	PrintValue(H);

	num = Delete(H);
	printf("删除的元素为:%d\n", num);
	PrintValue(H);
}


你可能感兴趣的:(C,数据结构,c语言,数据结构,二叉树,最小堆)