数据结构——堆的C语言代码实现

本文详细介绍了如何使用C语言实现数据结构中的最大堆和最小堆,包括创建、插入、删除和打印操作。通过具体代码展示了从数组下标1开始的存储策略,并提供了最大堆和最小堆的插入、删除算法。此外,还提供了一个测试用例以验证代码的正确性。
摘要由CSDN通过智能技术生成

系列文章目录

数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现
数据结构——队列的C语言代码实现
数据结构——堆的C语言代码实现



前言

本文主要学习如何实现最大队和最小堆的创建、插入、删除等。

一、堆的概念

堆是考虑特权的数据结构,被称作优先队列

在前面学习队列时,我们曾举例:在银行中排队处理业务,来解释队列“先进先出”的特点。
而在学习堆时,我们可以联想打印店排队:某一个用户需要打印数百页的资料,而排在他后面的顾客只需打印一两页的试题,那么此时店主和前客户一般都会同意优先处理后客户的需求。
堆是特殊的队列,最常用结构是完全二叉树又因为完全二叉树必的节点规律性极强,故常用数组实现堆的存储。
对于下标为i的节点,其父节点下标为i/2,其左右孩子节点下标为2i、2I+1

二、代码实现

1.Heap.h

主要实现创建、插入、删除和打印。最大堆与最小堆的接口函数一致。
注意在用数组存储堆时,我们使用的数组下标是从1开始的,空余的下标0用于存放规定的最大值或者最小值,便于插入时进行操作。
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#define MAX 10000000
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int DataType;
typedef struct Heap
{
	DataType* arr;
	int size;
	int capacity;
}*Heap;

//创建堆
Heap CreateHeap(int maxsize);

//检测是否已满
bool CheckFull(Heap h);

//检测是否已空
bool CheckEmpty(Heap h);

//插入
void Insert(Heap h, DataType x);

//删除
DataType Delete(Heap h);

//打印
void Print(Heap h);

2.Heap.c

最大堆与最小堆的接口函数实现大同小异。重点注意实现插入与删除时。使用的过滤方法!

(1)创建堆

因为从下标1开始存储,所以申请空间时,要申请maxsize+1个空间
代码如下:

//创建堆
Heap CreateHeap(int maxsize)
{
	Heap h = (Heap)malloc(sizeof(struct Heap));
	h->arr = (DataType*)malloc(sizeof(DataType) * (maxsize + 1));
	h->capacity = maxsize;
	h->size = 0;
	//数组从下标1开始存放数据,arr[0]存放最大值,
	//便于插入时进行过滤操作
	h->arr[0] = MAX;
	return h;
}

(2)检测是否已满

代码如下:

//检测是否已满
bool CheckFull(Heap h)
{
	return h->size == h->capacity;
}

(3)检测是否已空

代码如下:

//检测是否已空
bool CheckEmpty(Heap h)
{
	return h->size == 0;
}

(4)插入

主要思路:
1、先判断数组是否已满
2、将数组的size加一赋值为i,然后从数组最后一个下标i开始,依次用父节点(下标为2/i)与插入的数X比较大小
3、在最大堆中,如果父节点小于X,则将父节点下移到孩子节点,然后将i迭代,继续上述比较;在最小堆中,如果父节点大于X,则将父节点移到孩子节点,然后将i迭代,继续上述操作;
4、最终当判断条件结果为假时,X就找到了要插入的位置下标。
代码如下:

//最大堆插入
void Insert(Heap h, DataType x)
{
	if (CheckFull(h))
	{
		printf("最大堆已满!\n");
		return;
	}
	else
	{
		//最大堆插入元素后,最后的数据位置下标
		int i = ++h->size;
		//从最后一个位置向上过滤父节点
		//如果X大于父节点,则父节点下移
		for (; h->arr[i / 2] < x; i /= 2)
		{
			h->arr[i] = h->arr[i / 2];
		}
		//当X小于父节点,此时i就是要插入的位置
		h->arr[i] = x;
	}
}
//最小堆的插入
void Insert(Heap h, DataType x)
{
	if (CheckFull(h))
	{
		printf("\n");
		return;
	}
	else
	{
		int i = ++h->size;
		for (; h->arr[i / 2] > x; i /= 2)
		{
			h->arr[i] = h->arr[i / 2];
		}
		h->arr[i] = x;
	}
}

(5)删除

主要思路:
1、先判断数组是否已空;
2、取出最大值或者最小值(下标为1的数组元素);
3、然后删除最后一个元素的空间,将原数组的最后一个元素num从上到下,与兄弟节点中较大的进行比较,找到要插入的位置
即先从下标为1开始,它的两个孩子下标分别为2、3,先找到较大的孩子节点。假设是下标为2,用下标为2的元素与num相比。在最大堆中,如果num小,则将下标为1的元素赋值为下表为2的元素(节点上移),然后迭代继续比较,直到num较大,此时的父节点就是X要插入的位置。而在最小堆中,就是比较的结果恰恰相反。
代码如下:

//最大堆删除
DataType Delete(Heap h)
{
	if (CheckEmpty(h))
	{
		printf("最大堆已空!\n");
		exit(-1);
	}
	else
	{
		//取出最大元素
		int Max = h->arr[1];
		//用最后一个节点元素从上向下过滤
		int num = h->arr[h->size--];
		int parent, child;
		for (parent = 1; 2 * parent <= h->size; parent = child)
		{
			child = parent * 2;
			//找到两个孩子中较大的一个
			if (child != h->size && h->arr[child + 1] > h->arr[child])
				child += 1;
			//最后一个节点大于孩子节点,则找到了正确位置
			//最后一个节点插入到父节点
			if (num >= h->arr[child])
				break;
			else
				h->arr[parent] = h->arr[child];
		}
		h->arr[parent] = num;
		return Max;
	}
}

//最小堆删除
DataType Delete(Heap h)
{
	if (CheckEmpty(h))
	{
		printf("ѿ!\n");
		exit(-1);
	}
	else
	{
		DataType min = h->arr[1];
		DataType num = h->arr[h->size--];
		int parent, child;
		for (parent = 1; parent * 2 <= h->size; parent = child)
		{
			child = parent * 2;
			if (child != h->size && h->arr[child] > h->arr[child + 1])
				child += 1;
			if (h->arr[child] >= num)
				break;
			else
				h->arr[parent] = h->arr[child];
		}
		h->arr[parent] = num;
		return min;
	}
}

(6)打印

代买如下:

//打印
void Print(Heap h)
{
	int i = 1;
	for (; i <= h->size; i++)
	{
		printf("%d ", h->arr[i]);
	}
}

3.test.c

最大堆:

#include"MaxHeap.h"
int main()
{
	int maxsize = 100;
	Heap h = CreateMaxHeap(maxsize);
	int input = 0;
	int count = 0;
	while ((scanf("%d", &input) == 1)&&count<=maxsize)
	{
		Insert(h, input);
		count++;
	}
	printf("最大堆为:\n");
	Print(h);
	int max = Delete(h);
	printf("\n最大值是:%d\n", max);
	printf("最大堆为:\n");
	Print(h);
	return 0;
}

最小堆:

#include"Heap.h"
int main()
{
	int maxsize = 100;
	Heap h = CreateHeap(maxsize);
	int count = 0;
	int input = 0;
	while (scanf("%d", &input) == 1 && count <= maxsize)
	{
		Insert(h, input);
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("最小堆是:\n");
		Print(h);
		int min = Delete(h);
		printf("\n最小值是:%d\n", min);
		printf("最小堆是:\n");
		Print(h);
	}
	return 0;
}

总结

多分析代码,理解逐层过滤的方便之处。

数据结构——用C语言描述(第3版)》课后答案的描述使用C语言实现各种数据结构和算法。以下是对几个常见数据结构的描述和相关代码示例。 1. 数组(Array):数组是一种线性数据结构,用于存储相同类型的元素。C语言中使用数组可以快速访问和修改元素。示例代码如下: ```c #include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; for(int i = 0; i < 5; i++) { printf("%d ", arr[i]); } return 0; } ``` 2. 链表(Linked List):链表是一种动态数据结构,通过节点之间的指针链接来存储数据。C语言中可以使用结构体和指针来实现链表。示例代码如下: ```c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; }; void printList(struct Node* head) { struct Node* current = head; while(current != NULL) { printf("%d ", current->data); current = current->next; } } int main() { struct Node* head = NULL; struct Node* second = NULL; struct Node* third = NULL; head = (struct Node*) malloc(sizeof(struct Node)); second = (struct Node*) malloc(sizeof(struct Node)); third = (struct Node*) malloc(sizeof(struct Node)); head->data = 1; head->next = second; second->data = 2; second->next = third; third->data = 3; third->next = NULL; printList(head); return 0; } ``` 3. 栈(Stack):栈是一种后进先出(LIFO)的数据结构,在C语言中可以使用数组来实现。示例代码如下: ```c #include <stdio.h> #define MAX_SIZE 100 int stack[MAX_SIZE]; int top = -1; void push(int item) { if(top == MAX_SIZE - 1) { printf("Stack Overflow\n"); } else { stack[++top] = item; } } int pop() { if(top == -1) { printf("Stack Underflow\n"); return -1; } else { return stack[top--]; } } void printStack() { for(int i = top; i >= 0; i--) { printf("%d ", stack[i]); } } int main() { push(1); push(2); push(3); printf("Popped element: %d\n", pop()); printStack(); return 0; } ``` 这些示例代码展示了如何使用C语言描述《数据结构——用C语言描述(第3版)》中介绍的数据结构。读者可以根据书中提供的习题进行编程练习,进一步巩固数据结构和算法的相关知识。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值