【数据结构】实现可控创建大堆或小堆

【问题描述】:前面我们实现了一个小堆的创建,及一些接口,但在实际应用中,我们并不清楚用户到底是要创建大堆还是小堆,这就要求我们的代码能够根据用户实际需要处理问题,而不是固定的只能处理单一问题。

【解决思路】:我们知道创建大堆与小堆的区别在于比较堆中左右孩子时、比较孩子节点与双亲节点时,大堆取较大者,而小堆取较小者,然后继续后面的工作。我们可以创建一个函数指针变量,保存用户传递的比较堆中元素的方法。给出两种比较方法,然后根据用户要求来分别调用,完成最终的大堆或小堆。

具体实现代码如下:

BHeapSHeap.h:

typedef int HPDatatype;
typedef int (*PCOM)(HPDatatype, HPDatatype);
int Less(HPDatatype left, HPDatatype right);//堆中元素小于比较
int Greater(HPDatatype left, HPDatatype right);//堆中元素大于比较

typedef struct Heap
{
	HPDatatype* _array;
	int _capacity;
	int _size;
	PCOM Compare;//函数指针变量,保存用户传递的比较堆中元素的方法
}Heap;

//用数组初始化堆
void InitHeap(Heap* hp, HPDatatype* array, int size,PCOM compare);

//初始化一个空堆
void InitEmptyHeap(Heap* hp, int capacity, PCOM compare);

//在堆中插入值为data的元素
void InsertHeap(Heap* hp, HPDatatype data);

//删除堆顶元素
void EraseHeap(Heap* hp);

//获取堆中有效元素个数
int HeapSize(Heap* hp);

//检测堆是否为空堆
int HeapEmpty(Heap* hp);

//获取堆顶元素
HPDatatype HeapTop(Heap* hp);

//销毁堆
void DestoryHeap(Heap* hp);

初始化堆:将用户传递的比较方法作为参数传入,并按比较方法来初始化堆。

void Swap(HPDatatype* pLeft, HPDatatype* pRight) {
	HPDatatype tmp = *pLeft;
	*pLeft = *pRight;
	*pRight = tmp;
}

void AdjustDown(HPDatatype* array, int size, int parent, PCOM Compare) {
	int child = parent * 2 + 1;//child标记了左孩子

	while (child < size) {
		//找双亲中较小的孩子
		if (child + 1 < size && Compare(array[child + 1],array[child])) {
			child = child + 1;
		}

		if (Compare(array[child],array[parent])) {
			Swap(&array[child], &array[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			return;
	}
}

int Less(HPDatatype left, HPDatatype right) {
	return left < right;
}
int Greater(HPDatatype left, HPDatatype right) {
	return left > right;
}

void InitHeap(Heap* hp, HPDatatype* array, int size, PCOM compare) {
	assert(hp);
	hp->_array = (HPDatatype*)malloc(sizeof(HPDatatype)*size);
	if (hp->_array == NULL) {
		assert(0);
		return;
	}
	hp->_capacity = size;
	for (int i = 0; i < size; ++i)
		hp->_array[i] = array[i];
	hp->_size = size;
	hp->Compare = compare;

	//将该完全二叉树进行调整使其满足堆的性质

	//找完全二叉树中倒数第一个非叶子节点
	int root = ((size - 2) >> 1);
	for (; root >= 0; --root)
		AdjustDown(hp->_array, size, root,hp->Compare);
}

初始化空堆:同样需要传入用户的比较方法。

void InitEmptyHeap(Heap* hp, int capacity, PCOM compare) {
	assert(hp);
	hp->_array = (HPDatatype*)malloc(sizeof(HPDatatype)*capacity);
	if (hp->_array == NULL) {
		assert(0);
		return;
	}
	hp->Compare = compare;
	hp->_capacity = capacity;
	hp->_size = 0;
}

插入元素:在进行向上调整时,按照用户传入的方法比较堆中元素。

void AdjustUp(HPDatatype* array, int size, int child,PCOM Compare) {
	int parent = ((child - 1) >> 1);

	while (child) {
		if (Compare(array[child],array[parent])) {
			Swap(&array[child], &array[parent]);
			child = parent;
			parent = ((child - 1) >> 1);
		}
		else
			return;
	}

}

void CheckCapacity(Heap* hp) {
	assert(hp);
	if (hp->_size == hp->_capacity) {
		int newCapacity = hp->_capacity * 2;
		HPDatatype* pTemp = (HPDatatype*)malloc(sizeof(HPDatatype)*newCapacity);
		if (pTemp == NULL) {
			assert(0);
			return;
		}
		for (int i = 0; i < hp->_size; ++i)
			pTemp[i] = hp->_array[i];
		free(hp->_array);
		hp->_array = pTemp;
		hp->_capacity = newCapacity;
	}
}

void InsertHeap(Heap* hp, HPDatatype data) {
	CheckCapacity(hp);
	hp->_array[hp->_size] = data;
	hp->_size++;
	AdjustUp(hp->_array, hp->_size, hp->_size - 1,hp->Compare);
}

其余模块与之前小堆中的实现方法一样,此处不再赘述。下面我们来看一下最终的结果:

测试代码(小堆):

Heap hp;
	int array[] = { 2,6,7,3,9,1,4,0,5,8 };
	InitHeap(&hp, array, sizeof(array) / sizeof(array[0]),Less);
	printf("%d\n", HeapSize(&hp));
	printf("%d\n", HeapTop(&hp));

运行结果:

测试代码(大堆):

Heap hp;
	int array[] = { 2,6,7,3,9,1,4,0,5,8 };
	InitHeap(&hp, array, sizeof(array) / sizeof(array[0]),Greater);
	printf("%d\n", HeapSize(&hp));
	printf("%d\n", HeapTop(&hp));

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值