堆实现代码

本文介绍了如何使用C语言实现最大堆和最小堆的数据结构。代码包括了堆的初始化、插入、删除、获取堆顶元素、检查是否为空、获取元素个数以及销毁堆等操作,并提供了比较函数和相应的调整算法。示例代码展示了如何创建堆并进行插入、删除等操作,以及打印堆中的元素。
摘要由CSDN通过智能技术生成
  • heap.h
#pragma once
typedef int DType;
//函数指针的类型定义
typedef int (*PCOM)(DType left, DType right);

typedef struct  heap
{
	DType* array;
	int capacity;
	int size;
	PCOM pcom;//函数指针变量-->指向所有比较的函数
}heap;

int less(DType left, DType right);//比较函数
//初始化
heap* heapInit(heap* hp, DType*array, int size,PCOM pcom);

//插入
void heapInsert(heap* hp, DType data);
//删除
void heapdel(heap* hp);
//获取堆顶元素
DType heaptopdata(heap* hp);
//检测是否为空
int heapempty(heap* hp);
//获取堆里有效元素的个数
int heapsize(heap* hp);
//对的销毁
void heapdestory(heap* hp);
void adjust(heap* hp, int parent);
void swap(DType* left, DType* right);
void adjustup(DType* hp);
  • heap.c
#include"heap.h"

#include<assert.h>
#include<malloc.h>
#include<stdio.h>
int less(DType left, DType right){
	return left > right;
}
void swap(DType* left, DType* right){
	int temp = *left;
	*left = *right;
	*right = temp;
}
//初始化
heap* heapInit(heap* hp, DType*array, int size, PCOM pcom){
	assert(hp);
	int lastnotleaf = 0;
	hp->array = (DType*)malloc(sizeof(DType)*size);
	if (NULL == hp->array){
		return NULL;
	}	
	hp->capacity = size;
	//memcpy(hp->array, array, sizeof(sizeof(DType)*size));//以字节为准进行拷贝,大小为(sizeof(DType)*capa)
	for (int i = 0; i < size; i++){
		hp->array[i] = array[i];
	}

	hp->size = size;
	hp->pcom = pcom;//有了这种比较方式

	//找到非叶子结点
	lastnotleaf = ((size - 1) - 1) / 2;
	//从该结点位置逐个往前直到根
	for (int root = lastnotleaf; root >= 0; root--){
		adjust(hp, root);
	}
	return hp;
}
void adjustup(heap* hp){
	DType* array = hp->array;
	int size = hp->size;
	int child = size-1;
	int parent = (child - 1) / 2;
	while (child){
		if (hp->pcom(array[child] , array[parent]))
		{
			swap(&array[child], &array[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}

		else return;
	}
}
//调整
void adjust(heap* hp, int parent){
	DType* array = hp->array;
	int size = hp->size;
	//默认让child标记左孩子,因为parent可能不存在右孩子
	int child = parent * 2 + 1;
	while (child<size){
		//右孩子存在的情况:
		if (child + 1<size&&hp->pcom(array[child + 1],array[child])) //要注意&&两边的先后次序,如果比较左右孩子放在前面,会造成访问越界
		{
			child += 1;//让child标记右孩子
		}
		//检测parent是否满足情况
		if (hp->pcom(array[child],array[parent])){
			swap(&array[child], &array[parent]);
			//较大的双亲和孩子交换后,可能会导致子树不满足
			parent = child;
			child = parent * 2 + 1;
		}
		else{
			//如果双亲比孩子节点还小
			return;
		}
	}
}

//插入
void heapInsert(heap* hp, DType data){
	//首先确定堆是否已满
	if (hp->size == hp->capacity){
		//已满先进行扩容
		hp->array = (DType*)realloc(hp->array,sizeof(DType)*(hp->capacity)*2);
		if (NULL == hp->array){
			assert(0);
			return;
		}
		hp->capacity *= 2;
	}
	//先将data插入堆中
	hp->array[hp->size++] = data;
	//然后对插入后的孩子节点与其父节点进行比较,调换
	adjustup(hp);
}
//删除
void heapdel(heap* hp){
	//判断堆是否为空
	if (heapempty(hp)) return;
	//交换堆顶和堆尾元素
	swap(&hp->array[0], &hp->array[hp->size - 1]);
	//有效个数-1
	hp->size -= 1;
	//对现在的二叉树进行重新排序,再次成堆
	adjust(hp, 0);
}
//获取堆顶元素
DType heaptopdata(heap* hp){
	assert(!heapempty(hp));
	return hp->array[0];
}
//检测是否为空
int heapempty(heap* hp){
	assert(hp);
	return 0 == hp->size;
}
//获取堆里有效元素的个数
int heapsize(heap* hp){
	assert(hp);
	return hp->size;
}
//对的销毁
void heapdestory(heap* hp){
	assert(hp);
	if (hp->array){
		free(hp->array);
		hp->array = NULL;
		hp->capacity = 0;
		hp->size = 0;
	}
}

  • test.c
#include<stdio.h>
#include"heap.h"
int main(){
	int array[] = {2,3,4,5,6,7,8};
	heap hp;
	int size = sizeof(array) / sizeof(array[0]);
	heapInit(&hp, array, size,less);
	printf("size=%d\n", heapsize(&hp));
	printf("top=%d\n", heaptopdata(&hp));

	//heapInsert(&hp, 10);
	heapdel(&hp);
	printf("size=%d\n", heapsize(&hp));
	printf("top=%d\n", heaptopdata(&hp));
	for (int i = 0; i < hp.size; i++)
	{
		printf("%d\t", hp.array[i]);
	}
	printf("\n");
	heapInsert(&hp, 1);
	printf("size=%d\n", heapsize(&hp));
	printf("top=%d\n", heaptopdata(&hp));
	for (int i = 0; i < hp.size; i++)
	{
		printf("%d\t", hp.array[i]);
	}
}
  • 运行结果:

大堆:在这里插入图片描述

小堆:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值