最小-最大堆

《数据结构与算法分析——c语言描述》 练习6.15 答案


根据题目的两条要求,可以推出:

1.偶数层的儿子比父亲大(注意,不是偶数层的全部逐渐增大)

2.奇数层的儿子比父亲小(注意,不是奇数层的全部逐渐增大)

3.有1.2两条,可以知道,根节点是偶数层中最小的,第二层的两个结点其中一个是奇数层最大的(另一个可不一定是第二大!,因为这是两个不同的分支)。最低端的偶数层小于奇数层,由大小关系递推,所以知道最小元就是根节点。最大元位于第二层。


插入:

插入一个节点,根据层数判断符不符合小于(或大于)父亲,(可能存在交换),再和祖父比较,若符合则停止(可以根据插入法则推出偶数层奇数层是符合上面的1,2的)。不符合则上滤。


删除:

找出要找的元,然后根据层进行下滤。下滤的时候要判断是否符合规则,同时利用堆原有的大小关系。。。我也不知道怎么说。。。。反正自己推一下就行了。。。。。


这道题难的是想出来方法。。代码实现并不难。


参考:

blog.csdn.net/kinado/article/details/8552739     //这个代码好像是错的

josephpei.github.io/2013/12/23/minmaxheap-%E6%9C%80%E5%B0%8F%E6%9C%80%E5%A4%A7%E5%A0%86/           这个是正确的。


五月总结:

1-21日代码写得挺嗨的。最开心是10-20日。后面十天各种琐碎作业考试什么鬼的都要应付。。。

六月要考英语了。。。计划这个月发31篇吧。。。。

本来这篇是计划六月开始之前发的。凑够五月的30篇。可是要考汇编语言。当然最主要的原因是自己懒。



minmaxheap.h

#ifndef _MinMaxHeap_H
#define _MinMaxHeap_H
typedef int ElementType;

struct HeapStruct;
typedef struct HeapStruct *PriorityQueue;

PriorityQueue initialize(int maxElements);
PriorityQueue buildHeap(ElementType *arr, int n);
void destroy(PriorityQueue h);
void makeEmpty(PriorityQueue h);
void insert(ElementType X, PriorityQueue h);
ElementType deleteMin(PriorityQueue h);
ElementType deleteMax(PriorityQueue h);
int isEmpty(PriorityQueue h);
int isFull(PriorityQueue h);
//void decreaseKey(int pos, ElementType delta, PriorityQueue h);
//void increaseKey(int pos, ElementType delta, PriorityQueue h);
//void Delete(int pos, PriorityQueue h);
#endif // !_BinHeap_H




minmaxheap.cpp

#include"minmaxheap.h"
#include"fatal.h"

#define MinPQSize 1
#define MinData INT_MIN

struct HeapStruct {
	int capacity;
	int size;
	ElementType* elements;
};

PriorityQueue initialize(int maxElements) {
	PriorityQueue h;
	if (maxElements < MinPQSize)
		Error("Priority queue size is too small");
	h = (PriorityQueue)malloc(sizeof(struct HeapStruct));
	if (h == NULL)
		Error("OUT OF MEMORY");
	h->elements = (ElementType *)malloc(sizeof(ElementType)*(maxElements + 1));//多出来的一个用于存放最小的元素,其用来和堆顶比较
	if (h->elements == NULL)
		Error("OUT OF MEMORY");
	h->capacity = maxElements;
	h->size = 0;
	h->elements[0] = MinData;
	return h;
}

static int isEvenDepth(int pos) {//是不是偶数层
	while (pos > 1)//不是根节点
		pos = pos >> 2;//获得祖父
	return pos == 1;//此时pos只能在第一层和第二层
}

static void evenPercolateUp(int pos, PriorityQueue h) {//上滤,在偶数层逐渐向上
	ElementType elem = h->elements[pos];
	int i;
	for (i = pos; h->elements[i / 4] > elem; i /= 4)
		h->elements[i] = h->elements[i / 4];
	h->elements[i] = elem;
}

static void oddPercolateUp(int pos, PriorityQueue h) {//下滤,在奇数层逐渐向上
	ElementType elem = h->elements[pos];
	int i;
	for (i = pos; i > 3 && h->elements[i / 4] < elem; i /= 4)//i>3是为了不要冲过第二层
		h->elements[i] = h->elements[i / 4];
	h->elements[i] = elem;
}

static int evenPercolateDown(int pos, PriorityQueue h) {//偶数层下滤
	ElementType elem = h->elements[pos];
	int i, firstGrandChild, minGrandChild;
	for (i = pos; i < h->size; i = minGrandChild) {
		minGrandChild = firstGrandChild = i * 4;

		if (firstGrandChild > h->size) {//孙子越界
			int child = i * 2;
			if (child <= h->size) {//有孩子,child此时奇数层
				if (child<h->size && h->elements[child]>h->elements[child + 1]) //获得最小儿子
					child++;
				if (h->elements[child] < elem) {//奇数层儿子比偶数层父亲大,不符合规则,互换
					ElementType temp = h->elements[child];
					h->elements[child] = elem;
					elem = temp;
				}
			}
			break;
		}
		for (int i = 1; i < 4; i++) {//找最小的孙子
			if (firstGrandChild + i <= h->size&& h->elements[minGrandChild] > h->elements[firstGrandChild + i])
				minGrandChild = firstGrandChild + i;
		}

		if (elem > h->elements[minGrandChild]) {//要下滤
			h->elements[i] = h->elements[minGrandChild];
			int child = i * 2;//elem比最小孙子大,可能大于奇数层的两个儿子
			if (h->elements[child + 1] < h->elements[child])//找出最小儿子
				child++;
			if (h->elements[child] < elem)//奇数层父亲小于偶数层孙子,交换
			{
				ElementType temp = h->elements[child];
				h->elements[child] = elem;
				elem = temp;
			}
		}
		else
			break;
	}
	h->elements[i] = elem;
	return i;
}

static int oddPercolateDown(int pos, PriorityQueue h) {//奇数层下滤
	ElementType elem = h->elements[pos];
	int i, firstGrandChild, maxGrandChild;
	for (i = pos; i < h->size; i = maxGrandChild) {
		maxGrandChild = firstGrandChild = i * 4;

		if (firstGrandChild > h->size) {//孙子越界
			int child = i * 2;
			if (child <= h->size) {//有孩子,child此时偶数层
				if (child<h->size && h->elements[child]<h->elements[child + 1]) //获得最大儿子
					child++;
				if (h->elements[child] > elem) {//偶数层儿子比奇数层父亲大,不符合规则,互换
					ElementType temp = h->elements[child];
					h->elements[child] = elem;
					elem = temp;
				}
			}
			break;
		}
		for (int i = 1; i < 4; i++) {//找最大的孙子
			if (firstGrandChild + i <= h->size&& h->elements[maxGrandChild] < h->elements[firstGrandChild + i])
				maxGrandChild = firstGrandChild + i;
		}

		if (elem < h->elements[maxGrandChild]) {//要下滤
			h->elements[i] = h->elements[maxGrandChild];
			int child = i * 2;//elem比最大孙子小,可能小于偶数层的两个儿子
			if (h->elements[child + 1] > h->elements[child])//找出最大儿子
				child++;
			if (h->elements[child] >  elem)//偶数层父亲小于奇数层孙子,交换
			{
				ElementType temp = h->elements[child];
				h->elements[child] = elem;
				elem = temp;
			}
		}
		else
			break;
	}
	h->elements[i] = elem;
	return i;
}

PriorityQueue buildHeap(ElementType *arr, int n) {
	PriorityQueue h = initialize(n);

	h->size = n;
	for (int i = 0; i < n; i++) {
		h->elements[i + 1] = arr[i];
	}

	for (int i = n / 2; i > 0; i--) {
		if (isEvenDepth(i))
			evenPercolateDown(i, h);
		else
			oddPercolateDown(i, h);
	}
	return h;
}

void destroy(PriorityQueue h) {
	free(h->elements);
	free(h);
}

void makeEmpty(PriorityQueue h) {
	h->size = 0;
}

void insert(ElementType X, PriorityQueue h) {
	if (isFull(h))
		Error("priority queue is full");
	int i = ++h->size;
	h->elements[i] = X;
	if (i == 1)
		return;
	if (isEvenDepth(i)) {
		if (h->elements[i / 2] > h->elements[i])//父亲在奇数层
			evenPercolateUp(i, h);
		else {//奇数层父亲比偶数层儿子小
			ElementType temp = h->elements[i];
			h->elements[i] = h->elements[i / 2];
			h->elements[i / 2] = temp;
			oddPercolateUp(i / 2, h);
		}
	}
	else {//奇数层
		if (h->elements[i / 2] < h->elements[i])//父亲在偶数层
			oddPercolateUp(i, h);
		else {//偶数父亲比奇数层儿子大
			ElementType temp = h->elements[i];
			h->elements[i] = h->elements[i / 2];
			h->elements[i / 2] = temp;
			evenPercolateUp(i / 2, h);
		}
	}
}



ElementType deleteMin(PriorityQueue h) {//
	int i;
	ElementType minElement, lastElement;
	if (isEmpty(h))
		Error("priority queue is empty");
	minElement = h->elements[1];
	lastElement = h->elements[h->size--];//删除右下的元素
	h->elements[1] = lastElement;
	i = evenPercolateDown(1, h);
	return minElement;
}

int isEmpty(PriorityQueue h) {
	return h->size == 0;
}

int isFull(PriorityQueue h) {
	return h->size == h->capacity;
}



ElementType deleteMax(PriorityQueue h) {
	if (isEmpty(h))
		Error("EMPTY HEAP");
	if (h->size<=2)
		return h->elements[h->size--];
	else {
		int maxPos = 2;
		if (h->elements[3] > h->elements[2]) 			{
			maxPos = 3;
		}
		ElementType maxElement = h->elements[maxPos];
		ElementType lastElement = h->elements[h->size--];
		h->elements[maxPos] = lastElement;
		oddPercolateDown(maxPos, h);
		return maxElement;
	}
}

/*
void decreaseKey(int pos, ElementType delta, PriorityQueue h) {
	if (pos<1 || pos>h->size)
		Error("Positon Error");
	ElementType changedElem = h->elements[pos] - delta;
	int i;
	for (i = pos; h->elements[i / 2] > changedElem; i /= 2) {
		h->elements[i] = h->elements[i / 2];
	}
	h->elements[i] = changedElem;
}

void increaseKey(int pos, ElementType delta, PriorityQueue h) {
	if (pos<1 || pos>h->size)
		Error("Positon Error");
	ElementType changedElem = h->elements[pos] + delta;
	int i, child;
	for (i = pos; i < h->size; i = child) {
		child = i * 2;
		if (child > h->size)
			break;
		if (child != h->size&&h->elements[child] > h->elements[child + 1])
			child++;
		if (changedElem > h->elements[child])
			h->elements[i] = h->elements[child];
		else
			break;
	}
	h->elements[i] = changedElem;
}

void Delete(int pos, PriorityQueue h) {
	if (pos<1 || pos>h->size)
		Error("Positon Error");
	for (int i = pos; i > 1; i /= 2) {
		h->elements[i] = h->elements[i / 2];
	}
	deleteMin(h);
}
*/




main.cpp


#include"minmaxheap.h"
#include<stdlib.h>
#include<stdio.h>
#include"fatal.h"
#define N 20222

int RandInt(int i, int j) {
	int temp;
	temp = (int)(i + (1.0*rand() / RAND_MAX)*(j - i));
	return temp;
}

void getRandomInt(int *A, int n) {
	for (int i = 0; i < n; i++) {
		A[i] = i + 1;
	}

	for (int i = 1; i < n; i++) {
		//std::swap(A[i], A[RandInt(0, i)]);  
		int randAdrr = RandInt(0, i);
		int t = A[i];
		A[i] = A[randAdrr];
		A[randAdrr] = t;
	}
}


int main() {
	int a[N];
	getRandomInt(a, N);
	PriorityQueue h1 = initialize(N);
	PriorityQueue h2= buildHeap(a, N);

	for (int i = 0; i < N; i++) {
		insert(a[i], h1);
	}
	

	int cnt = 1;

	for (int i = 0; i < N; i++)
		if (cnt == deleteMin(h1) && cnt == deleteMin(h2))
			cnt++;
		else
			Error("error");
	destroy(h1);
	destroy(h2);


	PriorityQueue h3 = initialize(N);
	PriorityQueue h4 = buildHeap(a, N);

	for (int i = 0; i < N; i++) {
		insert(a[i], h3);
	}


	cnt = N;

	for (int i = 0; i < N; i++)
		if (cnt == deleteMax(h3) && cnt == deleteMax(h4))
			cnt--;
		else
			Error("error");
	destroy(h3);
	destroy(h4);

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值