#include <iostream> #include <vector> #include <queue> using namespace std; class BTree{ static const int M = 2; struct BTNode{ int keyNum; int key[2 * M - 1]; //关键字数组 struct BTNode* child[2 * M];//孩子结点数组 bool isLeaf; }; BTNode* root; //在插入时,保证pNode结点的关键字少于2*M-1个 void InsertNonFull(BTNode* pNode, int key); //当child结点有2M-1个关键字时,分裂此结点 void SplitChild(BTNode* parent, int i, BTNode* child); //两个M-1个元素的结点合并 void merge(BTNode* parent, BTNode* pNode1, BTNode* pNode2, int index); //找到比pNode结点第一个关键字小的最大的关键字,也就是前继结点 int predecessor(BTNode* pNode); //找到后继结点 int successor(BTNode* pNode); //pNode1向parent要一个结点key[index],parent向pNode0要一个结点,pNode1关键字个数为M-1 void ExchangeLeftNode(BTNode *parent, BTNode* pNode0, BTNode* pNode1, int index); void ExchangeRightNode(BTNode* parent, BTNode* pNode1, BTNode *pNode2, int index); //删除,结点关键字个数不少于M void RemoveNonLess(BTNode* pNode, int key); void DiskWrite(BTNode* pNode); void DiskRead(BTNode *pNode); BTNode* Search(BTNode* pNode, int key, int &index); public: BTree(); ~BTree(); BTNode* search(int key, int &index); void insert(int key); void remove(int key); //按层级打印。 void PrintRow(); }; BTree::BTree() { root = new BTNode(); root->isLeaf = true; root->keyNum = 0; DiskWrite(root); } BTree::~BTree() { struct BTNode* pNode; queue<struct BTNode*> q; q.push(root); while (!q.empty()){ pNode = q.front(); q.pop(); if (pNode->isLeaf) continue; for (int i = 0; i <= pNode->keyNum; i++) q.push(pNode->child[i]); delete pNode; } } void BTree::DiskWrite(BTNode* pNode) { } void BTree::DiskRead(BTNode *pNode) { } BTree::BTNode* BTree::Search(BTNode* pNode, int key, int &index) { int i = 0; while (i<pNode->keyNum&&key>pNode->key[i])//找到第一个大于等于key的下标 i++; if (i < pNode->keyNum&&key == pNode->key[i]){//如果找到关键字,返回 index = i; return pNode; } if (pNode->isLeaf)//已经搜到叶子结点,不存在 return NULL; else{ DiskRead(pNode->child[i]); return Search(pNode->child[i], key, index);//在第一个大于key值的孩子节点中递归搜索 } } void BTree::InsertNonFull(BTNode* pNode, int key) { int i = pNode->keyNum - 1; if (pNode->isLeaf){//如果是叶子结点,直接插入 while (i >= 0 && key < pNode->key[i]){ pNode->key[i + 1] = pNode->key[i]; i--; } pNode->key[i + 1] = key; pNode->keyNum++; DiskWrite(pNode); } else { while (i >= 0 && key < pNode->key[i]) i--;//找到第一个小于等于key的下标 i++; DiskRead(pNode->child[i]); if (pNode->child[i]->keyNum == 2 * M - 1){//判断孩子结点是否有2*M-1个关键字,有就需要分裂 SplitChild(pNode, i, pNode->child[i]); if (key>pNode->key[i])//如果key比上移到父节点的元素大 i++; } InsertNonFull(pNode->child[i], key);//已保证孩子结点关键字个数少于2*M-1个 } } void BTree::SplitChild(BTNode* parent, int i, BTNode* child) { int j; struct BTNode* pNode = new BTNode(); pNode->isLeaf = child->isLeaf; pNode->keyNum = M - 1; for (j = 0; j < M - 1; j++)//将child结点的后M-1个关键字赋给新节点 pNode->key[j] = child->key[j + M]; if (!child->isLeaf){//如果child不是叶子结点,将其后M个孩子结点赋给新节点。 for (j = 0; j < M; j++) pNode->child[j] = child->child[j + M]; } child->keyNum = M - 1; for (j = parent->keyNum; j > i; j--) parent->child[j + 1] = parent->child[j];//将child结点的父节点parent下标i以后的结点指针都向后移动一位, parent->child[j + 1] = pNode;//将新生成的结点当成parent的一个孩子 for (j = parent->keyNum - 1; j >= i; j--) //将i后面的关键字都向后移动一位 parent->key[j + 1] = parent->key[j]; parent->key[j + 1] = child->key[M - 1];//将孩子结点的中间结点移到父节点的指定位置 parent->keyNum++; DiskWrite(parent); DiskWrite(pNode); DiskWrite(child); } void BTree::merge(BTNode* parent, BTNode* pNode1, BTNode* pNode2, int index) { pNode1->key[M - 1] = parent->key[index]; for (int i = 0; i < M - 1; i++)//将pNode2的关键字移到pNode1中 pNode1->key[i + M] = pNode2->key[i]; pNode1->keyNum = 2 * M - 1; if (!pNode1->isLeaf){//如果不是叶子,将pNode2的孩子指针也移到pNode1中 for (int i = 0; i < M; i++) pNode1->child[i + M] = pNode2->child[i]; } for (int i = index; i < parent->keyNum; i++){//将父节点index以后的关键字以及孩子指针都向前移动一位 parent->key[i] = parent->key[i + 1]; parent->child[i + 1] = parent->child[i + 2]; } parent->keyNum--; delete pNode2; } int BTree::predecessor(BTNode* pNode) { while (!pNode->isLeaf) pNode = pNode->child[pNode->keyNum]; return pNode->key[pNode->keyNum - 1]; } int BTree::successor(BTNode* pNode) { while (!pNode->isLeaf) pNode = pNode->child[0]; return pNode->key[0]; } void BTree::ExchangeLeftNode(BTNode *parent, BTNode* pNode0, BTNode* pNode1, int index) { for (int i = pNode1->keyNum; i > 0; i--) pNode1->key[i] = pNode1->key[i - 1];//pNode1结点所有关键字向后移动一位 pNode1->key[0] = parent->key[index];//第0个关键字来自父节点 pNode1->keyNum++; parent->key[index] = pNode0->key[pNode0->keyNum - 1];//父节点的index处的关键字来自pNode0的最大关键字 if (!pNode0->isLeaf){//如果不是叶子结点, for (int i = pNode1->keyNum; i > 0; i--)//将pNode1的孩子指针都向后移动一位,并将pNode0的最后一个孩子指针赋给它的第一个 pNode1->child[i] = pNode1->child[i - 1]; pNode1->child[0] = pNode0->child[pNode0->keyNum]; } pNode0->keyNum--; } void BTree::ExchangeRightNode(BTNode* parent, BTNode* pNode1, BTNode *pNode2, int index) { pNode1->key[pNode1->keyNum] = parent->key[index]; pNode1->keyNum++; parent->key[index] = pNode2->key[0]; for (int i = 0; i < pNode2->keyNum - 1; i++) pNode2->key[i] = pNode2->key[i + 1]; if (!pNode2->isLeaf){ pNode1->child[pNode1->keyNum] = pNode2->child[0]; for (int i = 0; i < pNode2->keyNum; i++) pNode2->child[i] = pNode2->child[i + 1]; } pNode2->keyNum--; } void BTree::RemoveNonLess(BTNode* pNode, int key) { if (pNode->isLeaf){//到了叶子结点,直接删除 int i = 0; while (i<pNode->keyNum&&key>pNode->key[i]) i++; if (i < pNode->keyNum&&key == pNode->key[i]){ while (i < pNode->keyNum - 1){ pNode->key[i] = pNode->key[i + 1]; i++; } pNode->keyNum--; } else { cout << "not found!" << endl; } } else { int i = 0; while (i < pNode->keyNum&&key > pNode->key[i])//找到第一个大于等于key的关键字 i++; if (i < pNode->keyNum&&key == pNode->key[i]){//在结点中找到要删除的关键字 struct BTNode* pNode1 = pNode->child[i]; struct BTNode* pNode2 = pNode->child[i + 1]; if (pNode1->keyNum >= M){//如果关键字左边的孩子结点的关键字数大于等于M int target = predecessor(pNode1);//将其前继结点移到pNode中 pNode->key[i] = target; RemoveNonLess(pNode1, target);//递归删除target } else if (pNode2->keyNum >= M){//右边,同理 int target = successor(pNode2); pNode->key[i] = target; RemoveNonLess(pNode2, target); } else { merge(pNode, pNode1, pNode2, i);//都小于M,合并 RemoveNonLess(pNode1, key); } } else {//不在此结点中 struct BTNode *pNode1 = pNode->child[i]; struct BTNode *pNode0 = NULL; struct BTNode *pNode2 = NULL; if (i>0) pNode0 = pNode->child[i - 1];//左结点 if (i < pNode->keyNum) pNode2 = pNode->child[i + 1];//右结点 if (pNode1->keyNum == M - 1){//如果要删除的孩子结点关键字个数为M-1 if (i > 0 && pNode0->keyNum >= M){//如果左邻结点至少有M个关键字,向其借一个 ExchangeLeftNode(pNode, pNode0, pNode1, i - 1); } else if (i < pNode->keyNum&&pNode2->keyNum >= M){//同理, ExchangeRightNode(pNode, pNode1, pNode2, i); } else if (i>0){//两个相邻结点都只有M-1个关键字,合并 merge(pNode, pNode0, pNode1, i - 1); pNode1 = pNode0; } else{ merge(pNode, pNode1, pNode2, i); } RemoveNonLess(pNode1, key); } else{ RemoveNonLess(pNode1, key); } } } } BTree::BTNode* BTree::search(int key, int &index) { return Search(root, key, index); } void BTree::insert(int key) { struct BTNode* r = root; if (root->keyNum == 2 * M - 1){//根节点特殊处理,如果根节点关键字个数为2*M-1, struct BTNode* pNode = new BTNode();//新建一个结点作为新的根节点,并将现在的根节点作为 root = pNode;//新根节点的孩子结点 pNode->isLeaf = false; pNode->keyNum = 0; pNode->child[0] = r; SplitChild(pNode, 0, r);//孩子结点r有2*M-1个关键字 InsertNonFull(pNode, key); } else InsertNonFull(r, key); } void BTree::remove(int key) { if (root->keyNum == 1){//如果根节点只有两个孩子 struct BTNode* pNode1 = root->child[0]; struct BTNode* pNode2 = root->child[1]; if (pNode1->keyNum == M - 1 && pNode2->keyNum == M - 1){//且两个孩子都只有M-1个关键字,合并 merge(root, pNode1, pNode2, 0); delete root; root = pNode1; } else { RemoveNonLess(root, key); } } else { RemoveNonLess(root, key); } } void BTree::PrintRow() { struct BTNode* pNode; queue<struct BTNode*> q; q.push(root); while (!q.empty()){ pNode = q.front(); q.pop(); cout << "[ "; for (int i = 0; i < pNode->keyNum; i++) cout << pNode->key[i] << " "; cout << "]" << endl; if (pNode->isLeaf) continue; for (int i = 0; i <= pNode->keyNum; i++) q.push(pNode->child[i]); } } int main(void) { BTree tree; tree.insert('c'); tree.insert('n'); tree.insert('g'); tree.insert('a'); tree.insert('h'); tree.insert('e'); tree.insert('k'); tree.insert('q'); tree.insert('m'); tree.insert('f'); tree.insert('w'); tree.insert('l'); tree.insert('t'); tree.insert('z'); tree.insert('d'); tree.insert('p'); tree.insert('r'); tree.insert('x'); tree.insert('y'); tree.insert('s'); tree.remove('n'); tree.remove('b'); tree.PrintRow(); }
好吧,其实我只是把前面的c代码封装了一下,依旧是参考了《算法导论》以及http://blog.chinaunix.net/uid-20196318-id-3030529.html
时间: 2024-10-08 06:20:02