关闭

最小-最大堆

218人阅读 评论(0) 收藏 举报
分类:

《数据结构与算法分析——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);

}




0
0
查看评论

最大最小堆的插入与删除

最大堆、最小堆是一种用可用数组存储,并模拟实现二叉树的数据结构。 最大(小)堆具有以下的显著性质: ●最大(小)堆是一棵树,且是完全二叉树。 ●最大(小)堆是每个根节点都一定大(小)于等于其子节点。 ●在具体的存储时数组的[0]位置存放一个哨兵元素用于插入时防止越界,且由于这是 ...
  • Ava1anche
  • Ava1anche
  • 2015-07-20 11:05
  • 3028

C++实现堆、最大堆、最小堆 -- 堆排序插入删除操作

堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值。 最大堆和最小堆是二叉堆的两种形式。 最大堆:根结点的键值是所有堆结点键值中最大者。 最小堆:根结点的键值是所有堆结点键值中最小者。 而最大-最小堆集结了最大堆和最小堆的优点,这也是其名字的由来。 ...
  • FreeeLinux
  • FreeeLinux
  • 2016-08-09 15:10
  • 3802

最小堆。最大堆。

最大堆和最小堆是二叉堆的两种形式。 最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。 最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。 最小堆和最大堆的增删改相似,其实就是把算法中的大于改为小于,把小于改为...
  • Genios
  • Genios
  • 2012-11-08 23:00
  • 34739

最小最大堆

#include #include #include #include #define MAX_SIZE 100 #define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t)) typedef struct { int key; // other field }...
  • h1023417614
  • h1023417614
  • 2013-10-19 10:02
  • 585

【算法】堆,最大堆(大顶堆)及最小堆(小顶堆)的实现

此坑待埋。 点击打开漫谈经典排序算法:一、从简单选择排序到堆排序的深度解析链接 白话经典算法系列之七 堆与堆排序 二叉排序树与二叉堆 下面来说一说具体算法。
  • cdnight
  • cdnight
  • 2013-09-13 16:36
  • 56380

优先队列及最小堆最大堆

1 堆     1.1 简介 n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): (1)ki=号。//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子 若将此序列所存储的向量R[1..n]看做是一...
  • zhang20072844
  • zhang20072844
  • 2013-08-25 15:03
  • 24366

最大堆 最小堆 poj2442 STL堆的使用

最大堆最小堆代码实现 http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621 最大堆 最小堆原理图 http://www.cnblogs.com/wu8685/archive/2010/12/30/1922218.html ...
  • hnust_xiehonghao
  • hnust_xiehonghao
  • 2013-06-25 20:28
  • 4880

最小堆和最大堆的JAVA实现

/** * 文件名:BinaryHeap.java * 时间:2014年11月3日下午7:15:34 * 作者:修维康 */ package chapter6; import java.util.*; /** * 类名:BinaryHeap 说明:建立一个最小堆 */ class M...
  • xiuweikang
  • xiuweikang
  • 2014-11-04 16:37
  • 4536

基本数据结构之最大堆最小堆

基本数据结构之最大堆最小堆 堆是这样的一种数据结构,
  • luozhaowork
  • luozhaowork
  • 2013-08-30 19:22
  • 1061

最小-最大堆的实现

最小-最大堆的实现:/* 最小最大堆的性质: 1. 对于在偶数深度上的任意节点X,存储在X上的关键字小于它的父亲但是大于它的祖父 2. 对于在奇数深度上的任意节点X,存储在X上的关键字大于它的父亲但是小于它的祖父 从其中可以推理出: 1.任意节点X,其关键字的值必定在它的父亲和其祖父之...
  • kinado
  • kinado
  • 2013-01-29 14:57
  • 4505
    个人资料
    • 访问:73473次
    • 积分:1875
    • 等级:
    • 排名:千里之外
    • 原创:109篇
    • 转载:32篇
    • 译文:0篇
    • 评论:13条
    最新评论