二项队列

来源:互联网 发布:广发东财大数据精选 编辑:程序博客网 时间:2024/05/23 01:14
///heap.h~#ifndef _HEAP_H#define _HEAP_Hclass BinQueue{private:int currentSize;//当前结点数目int maxSize;//树的最多个数struct BinNode {int element; //结点的元素BinNode *parent;BinNode *child; //左孩子BinNode *sibling; //右邻居BinNode(int x = 0, BinNode* p = nullptr);//结点构造函数};//结点BinNode** BinTree; //二项树BinNode* combineTrees(BinNode* t1, BinNode* t2); //连接两棵树void traversal(BinNode* p); //前序遍历BinNode* findKey(BinNode* h, int key);BinQueue(int size,int current);//二项队列构造函数void destroy(BinNode* h);public:BinQueue(int size = 10); //二项队列构造函数~BinQueue();void insert(int x);//插入void findAndDecreaseKey(int k,int x);//找到值为x的关键字并减为kvoid decreaseKey(int k, BinNode* x);//减少关键字为kvoid merge(const BinQueue &h); //合并int deleteMin(); //删除最小值void print();//二项队列的输出};#endif


#include"heap.h"#include<algorithm>#include<cstdio>#include<climits>extern double sum1;BinQueue::BinNode::BinNode(int x,BinNode* p){parent = p;element = x;//存储结点child = sibling = nullptr;}BinQueue::~BinQueue(){for (int i = 0; i < maxSize; i++) {if (BinTree[i]) {destroy(BinTree[i]);}}}void BinQueue::destroy(BinNode* h){BinNode* child = h->child;BinNode* sibling = h->sibling;if(child)destroy(child);if(sibling)destroy(sibling);delete h;}//私有的构造函数,不为用户提供指定结点大小的方法BinQueue::BinQueue(int size,int current){currentSize = current; //存储当前结点数maxSize = size; //存储树的最大个数BinTree = new BinNode*[size]; //为二项树申请内存for (int i = 0; i < size; i++) {BinTree[i] = nullptr; //初始化每个树的根节点为null}}//构造函数,传入二项队列的大小BinQueue::BinQueue(int size){currentSize = 0; //存储当前结点数(初始为0)maxSize = size; //存储树的最大个数BinTree = new BinNode*[size]; //为二项树申请内存for (int i = 0; i < size; i++) {BinTree[i] = nullptr; //初始化每个树的根节点为null}}//找到关键字并减小(接口函数)//attention:统计时间时,find的时间不要计入void BinQueue::findAndDecreaseKey(int k, int x){BinNode* tmp = nullptr;for (int i = 0; i < maxSize; i++) {if (BinTree[i]) { tmp = findKey(BinTree[i], x); //搜索每一棵不为空的二项树if (tmp)break; //找到了退出循环}}if (tmp) { //如果存在,执行减少关键字的步骤;decreaseKey(k, tmp);}}//找到关键字BinQueue::BinNode* BinQueue::findKey(BinNode* h, int key){BinNode* p, *x = nullptr;p = h;while (p) {  //当p不为空时if (p->element == key)return p; //当前结点的值为key,返回当前结点else {x = findKey(p->child, key); //否则继续搜索其孩子if (x) return x;//在它的后代找到了关键字,返回其后代p = p->sibling; // 继续搜索其兄弟}}return nullptr;//没找到,则返回null}//减小关键字void BinQueue::decreaseKey(int k, BinNode* x){if (k >= x->element) return;//修改的值比原来大,不符合条件x->element = k;//更新关键字BinNode* now = x;BinNode* parent = now->parent; //记录当前结点及其父节点//父节点不为空,且父节点值大于当前结点时(违背了最小堆性质)while (parent != nullptr && now->element < parent->element) {std::swap(parent->element, now->element);//交换两者now = parent;//继续向上寻找parent = now->parent;}return;}//插入void BinQueue::insert(int x){if (currentSize == 0) { //如果没有结点,直接插入结点BinTree[0] = new BinNode(x);currentSize++;return;}//如果已经有结点,新建一个只含一个结点的二项队列,与其合并BinQueue *tmp = new BinQueue(maxSize,1);tmp->BinTree[0] = new BinNode(x);merge(*tmp);return;}//合并void BinQueue::merge(const BinQueue &h){int i, j;BinNode *t1, *t2;BinNode *carry = nullptr;//carry代表进位currentSize += h.currentSize;//更新当前结点数for (i = 0, j = 1; j <= currentSize; i++, j *= 2) {t1 = BinTree[i];t2 = h.BinTree[i];//   将三棵树的状态表示为二进制的形式//   | carry | t2 | t1 |//   null为0,非null为1//   总共有7种可能结果switch ((!!carry)*4 + (!!t2)*2 + !!t1) {case 0:/*000*/case 1:/*001*/break;case 2:/*010*/BinTree[i] = t2, h.BinTree[i] = nullptr;break;case 3:/*011*/carry = combineTrees(t1, t2);h.BinTree[i] = BinTree[i] = nullptr;break;case 4:/*100*/BinTree[i] = carry, carry = nullptr; break;case 5:/*101*/carry = combineTrees(t1, carry);BinTree[i] = nullptr;break;case 6:/*110*/carry = combineTrees(t2, carry);h.BinTree[i] = nullptr; break;case 7:/*111*/BinTree[i] = carry;carry = combineTrees(t1, t2);h.BinTree[i] = nullptr;break;}}}//连接BinQueue::BinNode* BinQueue::combineTrees(BinNode* t1, BinNode* t2){//维护t1始终小于t2,保证t1为根节点,t2是其孩子if (t1->element > t2->element) {std::swap(t1, t2);}t2->parent = t1;//t2在成为t1的孩子之前,t1的孩子先成为它的兄弟t2->sibling = t1->child;//t2再成为t1的孩子t1->child = t2;return t1;}//输出二项队列void BinQueue::print(){for (int i = 0; i < maxSize; i++) {if (BinTree[i] != nullptr) {//不为空的话printf("Tree %d: ",i);traversal(BinTree[i]);//输出其元素printf("\n");}}printf("\n");return;}//前序遍历void BinQueue::traversal(BinNode* p){if (!p)return;if (!p->parent)printf("(%d null),",p->element);elseprintf("(%d %d),", p->element,p->parent->element);traversal(p->child);//继续搜索孩子traversal(p->sibling);//继续搜索邻居}int BinQueue::deleteMin(){int i, j, minTree;BinNode* deleteTree = nullptr;BinNode* oldRoot = nullptr;int min = INT_MAX;if (currentSize == 0)return -1;//找到最小的树,记录最小元素及其下标for (i = 0; i < maxSize; i++) {if (BinTree[i] && BinTree[i]->element < min) {min = BinTree[i]->element;minTree = i;}}deleteTree = BinTree[minTree];//临时存储要删除的那个结点BinTree[minTree] = nullptr;//删除结点oldRoot = deleteTree; //记录要删除的结点deleteTree = deleteTree->child; //跟踪要删除结点的孩子结点free(oldRoot);//释放删除结点的内存BinQueue deleteQueue(maxSize,((1 << minTree) - 1));//被删除后树的大小为2^minTree - 1,其中minTree为其下标//当一个树被删除根结点后,相当于100…000 -> 11…111//所以只需要去除根结点的子树一个个后移即可for (j = minTree - 1; j >= 0; j--) {deleteTree->parent = nullptr;deleteQueue.BinTree[j] = deleteTree; deleteTree = deleteTree->sibling;deleteQueue.BinTree[j]->sibling = nullptr;}currentSize -= deleteQueue.currentSize + 1;//更新删除结点后二项队列的结点数merge(deleteQueue);//将删除结点的子树与原二项队列合并return min;}


0 0