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