《数据结构与算法分析——c语言描述》 练习6.32 答案
避免merge(H,H)
H2中没有树留下且Carry树为NULL,修改merge例程以终止合并
修改merge使得较少的树总被合并到较大的树中
binomialqueue.h
#ifndef _BinomialQueue_H #define _BinomialQueue_H typedef int ElementType; struct BinNode; typedef struct BinNode *BinTree; typedef struct Collection *BinQueue; BinQueue initialize(void); ElementType findMin(BinQueue h); int isEmpty(BinQueue h); BinQueue merge(BinQueue &h1, BinQueue &h2); void insert(ElementType X, BinQueue h); BinQueue deleteMin(BinQueue h); #endif // !_BinHeap_H
binomialqueue.cpp
#include"binomialqueue.h" #include"fatal.h" #define MAXTREES 25 #define CAPACITY ((1<<MAXTREES)-1)//容量是2^0+2^1+2^3+2^(MAXTREES-1) typedef struct BinNode *Position; struct BinNode { ElementType element; Position leftChild; Position nextSibling; }; struct Collection { int currentSize; BinTree theTrees[MAXTREES]; }; BinQueue initialize(void) { BinQueue h = (BinQueue)malloc(sizeof(struct Collection)); if (h == NULL) Error("OUT OF MEMORY"); for (int i = 0; i < MAXTREES; i++) h->theTrees[i] = NULL; h->currentSize = 0; return h; } ElementType findMin(BinQueue h) { if (isEmpty(h)) Error("EMPTY HEAP"); ElementType minElem; int i, j; for (i = 0, j = 1; j <= h->currentSize; i++, j *= 2) {//找到第一个的二项树的根,j代表i二项树结点的个数,最大的二项树的下一个二项树的结点的个数比currentSize的最大值大1 if (h->theTrees[i] != NULL) { minElem = h->theTrees[i]->element; break; } } for (; j <= h->currentSize; i++, j *= 2) {//再和剩下的比较 if (h->theTrees[i] && h->theTrees[i]->element < minElem) { minElem = h->theTrees[i]->element; } } return minElem; } int isEmpty(BinQueue h) { return h->currentSize == 0; } static BinTree combineTrees(BinTree t1, BinTree t2) { if (t1->element > t2->element) return combineTrees(t2, t1); else { t2->nextSibling = t1->leftChild;//leftchild指向高度高的二项树,高度依次从nextSibling减少 t1->leftChild = t2; return t1; } } BinQueue merge(BinQueue &h1, BinQueue &h2) {//h2合并到h1当中 if (h1 == h2) return h1; BinTree t1, t2; BinTree carry = NULL; int carrt_tag; if (h1->currentSize + h2->currentSize > CAPACITY) Error("TOO MUCH ELEM"); if (h1->currentSize < h2->currentSize) { //互换 BinQueue temp; temp = h1; h1 = h2; h2 = temp; } h1->currentSize += h2->currentSize; int h2Size = 0; for (int i = 0, j = 1; j <= h1->currentSize; i++, j *= 2) {//统计h2中树的数量 if (h2->theTrees[i] != NULL) h2Size++; } for (int i = 0, j = 1; (carry || h2Size) && j <= h1->currentSize; i++, j *= 2) { t1 = h1->theTrees[i]; t2 = h2->theTrees[i]; if (carry) carrt_tag = 1; else carrt_tag = 0; switch (!!t1 + 2 * !!t2 + 4 * carrt_tag) { case 0://t1,t2,carry空 break; case 1://t1非空 break; case 2://t2非空 h1->theTrees[i] = t2; h2->theTrees[i] = NULL; h2Size--; break; case 3://t1,t2非空 carry = combineTrees(t1, t2); h1->theTrees[i] = NULL; h2->theTrees[i] = NULL; h2Size--; break; case 4://carry非空 h1->theTrees[i] = carry; carry = NULL; break; case 5://t1,carry非空 carry = combineTrees(t1, carry); h1->theTrees[i] = NULL; break; case 6://t2, carry非空 carry = combineTrees(t2, carry); h2->theTrees[i] = NULL; h2Size--; break; case 7: h1->theTrees[i] = carry; carry = combineTrees(t1, t2); h2->theTrees[i] = NULL; h2Size--; break; default: Error("error"); break; } } return h1; } void insert(ElementType X, BinQueue h) { BinTree t1; BinTree carry = (BinTree)malloc(sizeof(struct BinNode)); if (carry == NULL) Error("EMPTY MEOERY"); carry->element = X; carry->leftChild = carry->nextSibling = NULL; int carrt_tag; if (h->currentSize + 1 > CAPACITY) Error("TOO MUCH ELEM"); h->currentSize += 1; int i = 0; while (carry != NULL) { t1 = h->theTrees[i]; if (carry) carrt_tag = 1; else carrt_tag = 0; switch (!!t1 + 2 * !!carrt_tag) { case 0://t1,t2,carry空 break; case 1://t1非空 break; case 2://carry非空 h->theTrees[i] = carry; carry = NULL; break; case 3://t1,carry非空 carry = combineTrees(t1, carry); h->theTrees[i] = NULL; break; default: Error("error"); break; } i++; } } BinQueue deleteMin(BinQueue h) { if (isEmpty(h)) Error("EMPTY HEAP"); int minTree; ElementType minElem; int i, j; for (i = 0, j = 1; j <= h->currentSize; i++, j *= 2) { if (h->theTrees[i] != NULL) { minElem = h->theTrees[i]->element; minTree = i; i++; break; } } for (; j <= h->currentSize; i++, j *= 2) { if (h->theTrees[i] && h->theTrees[i]->element < minElem) { minElem = h->theTrees[i]->element; minTree = i; } } BinQueue deleteQueue = initialize(); deleteQueue->currentSize = (1 << minTree) - 1;//mintree的儿子有mintree个,结点个数加起来就是 (1 << minTree) - 1 Position p = h->theTrees[minTree]->leftChild;//高度从大到小 for (int i = minTree - 1; i >= 0; i--, p = p->nextSibling) { deleteQueue->theTrees[i] = p; } free(h->theTrees[minTree]); h->theTrees[minTree] = NULL; h->currentSize -= (deleteQueue->currentSize + 1); merge(h, deleteQueue); free(deleteQueue); return h; }
main.cpp
#include"binomialqueue.h" #include<stdlib.h> #include<stdio.h> #include"fatal.h" 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 a[99999999]; int main() { int n; scanf("%d", &n); //int *a = malloc(sizeof(int)*n); //if (a == NULL) // fprintf(stderr,"out of memory"); getRandomInt(a, n); BinQueue h = initialize(); for (int i = 0; i < n; i++) insert(a[i], h); int cnt = 1; for (int i = 0; i < n; i++) { if (cnt == findMin(h)) cnt++; h= deleteMin(h); } //destroy(h); //free(a); }