学习笔记:B+树模拟数据库索引查找
来源:互联网 发布:软件质量分析报告 编辑:程序博客网 时间:2024/06/05 21:53
#include <iostream>#include <queue>using namespace std;/******************************PROGRAMER: FanchenxinM 阶B+树: (1) 非叶子节点key 个数和子树指针最大个数均为M. (2) 非叶子节点的key 为其子树节点M个key的最大或最小key.? (3) 叶子节点保存所有的key .B+的特性: 1.所有关键字都出现在叶子结点的链表中(稠密索引), 且链表中的关键字恰好是有序的 2.不可能在非叶子结点命中; 3.非叶子结点相当于是叶子结点的索引(稀疏索引), 叶子结点相当于是存储(关键字)数据的数据层; 4.更适合文件索引系统******************************//* 表结构 */typedef struct _TableStruct_{ char name[20]; // 名字作为索引的关键字,经过某种运算成为一个整数关键字,假设名字没有重名的情况 int age; char addr[256];}TABLE_ST;static TABLE_ST peopleInfoTable[20] = { {"杨洋", 20, "河北省秦皇岛市"}, {"张占音", 21, "河南省许昌市"}, {"沈东镇", 23, "黑龙江省讷河"}, {"孟苏", 15, "河北省石家庄"}, {"杨大勇", 20, "河北省唐山市"}, {"李桂珍", 12, "上海市"}, {"钱伟", 23, "福建省宁德"}, {"蔡景观", 14, "陕西省宝鸡"}, {"孙大宝", 35, "内蒙古包头"}, {"赵国", 23, "四川省"}, {"杨过", 21, "辽宁省大连市"}, {"张勇", 21, "河南省许昌市"}, {"沈陈东", 27, "江西省许昌市"}, {"孟大海", 56, "海南"}, {"杨治国", 34, "山东省"}, {"李正", 14, "北京市"}, {"钱爱装", 23, "山西省"}, {"蔡大头", 14, "厦门市"}, {"孙树", 35, "辽宁省沈阳市"}, {"赵本山", 60, "辽宁省铁岭市"},}; //人口信息表#define M (4)typedef struct _BPlusTreeNode_{ int keyNum; int key[M]; bool isLeaf; struct _BPlusTreeNode_* subTree[M]; struct _BPlusTreeNode_* father; //struct _BPlusTreeNode_* nextLeaf; // 只有是叶子节点的时候才用到 void* dataAddr[M]; //叶子节点指向的数据地址}BPlusTreeNode;BPlusTreeNode* newBPlusTreeNode(bool is_Leaf){ BPlusTreeNode* newNode = (BPlusTreeNode*)malloc(sizeof(BPlusTreeNode)); if(newNode != NULL) { newNode->keyNum = 0; memset(newNode->key, 0, (M) * sizeof(int)); newNode->isLeaf = is_Leaf; memset(newNode->subTree, NULL, M * sizeof(BPlusTreeNode*)); newNode->father = NULL; memset(newNode->dataAddr, NULL, M * sizeof(void*)); } else return NULL; return newNode;}/* father为需要分裂的节点的父节点 splitChildIdx 为需要分裂的节点的index, */void splitChild(BPlusTreeNode* father, int splitChildIdx, int key){ if(!father) return; /*father->subTree[splitChildIdx] 为需要分裂的节点,分裂完后作为 父节点subTree相应位置的左孩子*/ BPlusTreeNode* leftChild = father->subTree[splitChildIdx]; BPlusTreeNode* rightChild = newBPlusTreeNode(true); /* 新分裂出来的节点放在分裂点的右边 */ rightChild->father = father; int i = 0, mid = M / 2; // 左孩子mid个key, 右孩子 M-mid个key if(mid == 1){ // 为了保证至少有两个key mid++; if(leftChild->key[mid-1] > key) mid--; } for(; i < M-mid; i++) { rightChild->key[i] = leftChild->key[i+mid]; /* 将分裂节点的后M-mid个KEY给右孩子 */ } memset(&leftChild->key[mid], 0, sizeof(int)*(M-mid)); /* 清空分裂节点后面的M-mid个KEY 值 */ leftChild->keyNum = mid; rightChild->keyNum = M-mid; /* 如果该分裂节点不是叶子节点,也就是说它存在子节点 则需要将后面T个子节点送给右节点*/ if(leftChild->isLeaf == false){ rightChild->isLeaf = false; for(i = 0; i < M-mid; i++){ rightChild->subTree[i] = leftChild->subTree[i+mid]; rightChild->subTree[i]->father = rightChild; } /* 同时清除分裂节点的后面T个子节点指针 */ memset(&leftChild->subTree[mid], NULL, sizeof(BPlusTreeNode*) * (M-mid)); } else{ for(i = 0; i < M-mid; i++){ rightChild->dataAddr[i] = leftChild->dataAddr[i+mid]; } memset(&leftChild->dataAddr[mid], NULL, sizeof(void*)*(M-mid)); } int j = father->keyNum; for(i = father->keyNum-1; i > splitChildIdx; i--){ father->key[j] = father->key[i]; father->subTree[j] = father->subTree[i]; j--; } father->key[splitChildIdx] = leftChild->key[0]; /* 将分裂节点的中间KEY 放到父节点的KEY数组中 */ father->key[splitChildIdx+1] =rightChild->key[0]; father->subTree[splitChildIdx+1] = rightChild; if(father->keyNum == 0) father->keyNum += 2; else father->keyNum++; return; }/* sm_key 是pNode 的subTree[index]节点的最小key */void adjustKey(BPlusTreeNode* pNode, int sm_key, int index){ if(!pNode) return; if(index != 0){ pNode->key[index] = sm_key; } else{ pNode->key[index] = sm_key; int i = 0; if(pNode->father != NULL){ for(; i < pNode->father->keyNum; i++){ if(pNode->father->subTree[i] == pNode) break; } /* 继续向上调整最小key */ adjustKey(pNode->father, sm_key, i); } }}/*往节点KEY个数未满的节点处插入key值*/void insertKeyNotFull(BPlusTreeNode* pNode, int key, void* dataAddr){ if(!pNode) return; int idx = pNode->keyNum - 1; if(pNode->isLeaf == true){ if(pNode->keyNum == 0){ pNode->key[0] = key; pNode->keyNum = 1; pNode->dataAddr[0] = dataAddr; return; } for(; idx >= 0; idx--) { if(key < pNode->key[idx]){ pNode->key[idx+1] = pNode->key[idx]; pNode->dataAddr[idx+1] = pNode->dataAddr[idx]; } else break; }idx = idx + 1; if(idx == 0){ pNode->key[0] = key; pNode->dataAddr[0] = dataAddr; if(pNode->father){ int i = 0; for(; i < pNode->father->keyNum; i++){ if(pNode->father->subTree[i] == pNode) break; } adjustKey(pNode->father, pNode->key[0], i); } }else{ pNode->key[idx] = key; pNode->dataAddr[idx] = dataAddr; } pNode->keyNum++; } else{ for(idx = pNode->keyNum-1; idx >= 0; idx--){ if(key > pNode->key[idx]) break; } if(idx < 0) idx = 0; pNode = pNode->subTree[idx]; if(pNode->keyNum >= M){ splitChild(pNode->father, idx, key); if(pNode->father->subTree[idx+1]->keyNum == 1 || key > pNode->father->key[idx+1]) pNode = pNode->father->subTree[idx+1]; } insertKeyNotFull(pNode, key, dataAddr); } return;}void insertKey(BPlusTreeNode** root, int key, void* dataAddr){ if(*root == NULL){ *root = newBPlusTreeNode(true); } BPlusTreeNode* pCur = *root; if(pCur->keyNum == M){ BPlusTreeNode* newRoot = newBPlusTreeNode(false); newRoot->subTree[0] = *root; newRoot->subTree[0]->father = newRoot; *root = newRoot; splitChild(newRoot, 0, key); insertKeyNotFull(newRoot, key, dataAddr); } else{ insertKeyNotFull(*root, key, dataAddr); } return;}void printKey(int* arry, int n, int layer){ int i = 0;cout << "<" << layer << "> "; for(; i < n; i++) printf("%x ", arry[i]);}static int layer = 1;/* 深度优先遍历: layer 为该节点所在的层*/void DPSearch(BPlusTreeNode* pNode){ if(pNode == NULL) return; printKey(pNode->key, pNode->keyNum, layer); int i = 0; layer++; for(; i < pNode->keyNum; i++){DPSearch(pNode->subTree[i]); } layer--; return;}/* 广度优先遍历 */void BPSearch(BPlusTreeNode* pNode){if(pNode == NULL)return;queue<BPlusTreeNode*> q;q.push(pNode);BPlusTreeNode* pCur = NULL;while(!q.empty()){pCur = q.front();printKey(pCur->key, pCur->keyNum, 0);q.pop();int i = 0;for(; i < pCur->keyNum; i++){if(pCur->subTree[i]){q.push(pCur->subTree[i]);}}}}/* 姓名字符串转换为索引键值 */int nameToKey(const char* name){ int len = strlen(name); int key = 0, n = len-1; for(; n >= 0; n--){int diff = 0;if(name[n] > '0')diff = name[n] - '0';elsediff = '0' - name[n]; key += diff; } return key / len;}BPlusTreeNode* searchKey(BPlusTreeNode* pCur, int key, int* keyIndex){ if(pCur== NULL) return NULL; int i = 0; if(pCur->isLeaf){ for(i = 0; i < pCur->keyNum; i++){ if(pCur->key[i] == key) break; } if(i >= pCur->keyNum) return NULL; *keyIndex = i; return pCur; } else{ for(i = pCur->keyNum - 1; i >= 0; i--){ if(key >= pCur->key[i]) break; } if(i < 0){ cout << "no match subTree, key = " << key << "; small key = " << pCur->key[0] << endl; return NULL; } return searchKey(pCur->subTree[i], key, keyIndex); }}void searchInfoByName(BPlusTreeNode* pRoot, const char* name){ if(!pRoot || !name) return; int keyIndx = 0, key = 0; key = nameToKey(name); BPlusTreeNode* leaf = searchKey(pRoot, key, &keyIndx); if(leaf){ cout << name << " 的索引key 值为: 0x" << hex << key << endl; TABLE_ST* personInfo = (TABLE_ST*)leaf->dataAddr[keyIndx]; cout << "年龄: " << dec << personInfo->age << endl; cout << "家庭住址: " << personInfo->addr << endl; } else cout << "找不到" << name << " 的相关信息" << endl; return;}BPlusTreeNode* create_BPlusTree(const TABLE_ST* table, int rowNum){ BPlusTreeNode* root = newBPlusTreeNode(true); //BPlusTreeNode* LeafHead = newBPlusTreeNode(true); //LeafHead->nextLeaf = root; if(root){ int i = 0; for(; i < rowNum; i++){ int key = nameToKey(table[i].name); insertKey(&root, key, (void*)&table[i]); } } return root;}/* pNode 需要删除的key 在该节点里 isLeft标识找到的兄弟是左兄弟还是右兄弟 index 为pNode 在父节点的subTree数组中的位置 返回值为true 表示找到否则没找到 */bool checkBrotherIsRich(BPlusTreeNode* pNode, int index, bool* isLeft) { if(pNode == NULL) return false; if(pNode->father == NULL) return false; BPlusTreeNode* father = pNode->father; if(index == 0) //如果该节点是最左边的孩子,则只存在右兄弟 { if(father->subTree[index+1]->keyNum > 2){ *isLeft = false; return true; } else return false; } if(index == father->keyNum-1) //如果该节点是最右边的孩子,则只存在左兄弟 { if(father->subTree[index-1]->keyNum > 2){ *isLeft = true; return true; } else return false; } /* 一般是先从左兄弟开始判断,移动左兄弟的key 比较方便,不会产生最小key 变化的问题,不需要 向上调整*/ if(index > 0 && index < father->keyNum-1){ if(father->subTree[index-1]->keyNum > 2){ *isLeft = true; return true; } else{ if(father->subTree[index+1]->keyNum > 2){ *isLeft = false; return true; } else return false; } } return false;}/* 将arry 数组index 后面的内容前移一个单位到index 位置 */template<typename T>void moveProcess(T arry[], int index, int n){ int i = index, j = index + 1; for(; j < n; j++){ arry[i++] = arry[j]; } arry[i] = 0;}/* 如果兄弟节点都不富裕,父节点执行合并或旋转操作 sub_idx为需要合并或旋转操作的节点在pNode的subTree[]的index*/void mergeOrRotate(BPlusTreeNode* pNode){ if(!pNode) return; if(pNode->father == NULL){ // pNode 为根节点 且 keyNum == 1, 将根节点指针指向子节点 BPlusTreeNode* child = pNode->subTree[0]; /* 将子节点的所有拷贝给根节点 */ int i = 0; for(; i < child->keyNum; i++){ pNode->key[i] = child->key[i];if(child->isLeaf == false){pNode->subTree[i] = child->subTree[i];pNode->subTree[i]->father = pNode;}else{pNode->dataAddr[i] = child->dataAddr[i];pNode->subTree[i] = NULL;} } pNode->keyNum = child->keyNum; free(child); child = NULL; return; } BPlusTreeNode* pFather = pNode->father; int sub_idx = 0; for(; sub_idx < pFather->keyNum; sub_idx++){ if(pFather->subTree[sub_idx] == pNode) break; } bool isLeft = false; if(checkBrotherIsRich(pNode, sub_idx, &isLeft)){ if(isLeft){ // 如果左兄弟富裕 keyNum > 2 /* 将左兄弟的最右的分支借过来(右旋操作) */ BPlusTreeNode* pLeftBrother = pFather->subTree[sub_idx-1]; int i = pNode->keyNum - 1; for(; i >= 0; i--){ pNode->key[i+1] = pNode->key[i]; pNode->subTree[i+1] = pNode->subTree[i]; //pNode->dataAddr[i+1] = pNode->dataAddr[i]; } int n = pLeftBrother->keyNum-1; pNode->key[0] = pLeftBrother->key[n]; pNode->subTree[0] = pLeftBrother->subTree[n]; pNode->subTree[0]->father = pNode; //pNode->dataAddr[0] = pLeftBrother->dataAddr[n]; pLeftBrother->key[n] = 0; pLeftBrother->subTree[n] = NULL; //pLeftBrother->dataAddr[n] = NULL; pLeftBrother->keyNum--; pNode->keyNum++; adjustKey(pFather, pNode->key[0], sub_idx); } else{ // 如果右兄弟富裕 keyNum > 2 BPlusTreeNode* pRightBrother = pFather->subTree[sub_idx+1]; int n = pNode->keyNum; pNode->key[n] = pRightBrother->key[0]; pNode->subTree[n] = pRightBrother->subTree[0]; pNode->subTree[n]->father = pNode; //pNode->dataAddr[n] = pRightBrother->dataAddr[0]; moveProcess(pRightBrother->key, 0, pRightBrother->keyNum); moveProcess(pRightBrother->subTree, 0, pRightBrother->keyNum); //moveProcess(pRightBrother->dataAddr, 0, pRightBrother->keyNum); pRightBrother->key[pRightBrother->keyNum-1] = 0; pRightBrother->subTree[pRightBrother->keyNum-1] = NULL; //pRightBrother->dataAddr[pRightBrother->keyNum-1] = NULL; pRightBrother->keyNum--; pNode->keyNum++; adjustKey(pFather, pRightBrother->key[0], sub_idx+1); } } else{ // 如果左右兄弟都不富裕 /* 将其和左或右兄弟合并 合并将保留左节点*/ BPlusTreeNode* pLeft = NULL, *pRight = NULL; int keep_id = 0; if(sub_idx == 0){ pLeft = pNode; pRight = pFather->subTree[sub_idx+1]; keep_id = sub_idx; } else{ pLeft = pFather->subTree[sub_idx-1]; pRight = pNode; keep_id = sub_idx -1; } int n_l = pLeft->keyNum, n_r = pRight->keyNum; int i = n_l, j = 0; for(; j < n_r; j++){ pLeft->key[i] = pRight->key[j]; pLeft->subTree[i] = pRight->subTree[j]; pLeft->subTree[i]->father = pLeft; i++; } pLeft->keyNum = i; moveProcess(pFather->key, keep_id+1, pFather->keyNum); moveProcess(pFather->subTree, keep_id+1, pFather->keyNum); pFather->keyNum--; free(pRight); pRight = NULL; /* 如果合并后父节点的keyNum < 2 则递归调用 */ if(pFather->keyNum < 2){ mergeOrRotate(pFather); } } return;}/* pNode 是叶子节点,sub_idx 为其在父节点subTree 中的索引 */void leafMergeAndDelete(BPlusTreeNode* pNode, int sub_idx, int deleteKey){ if(pNode == NULL) return; BPlusTreeNode* pFather = pNode->father; /* 先删除deleteKey */ int oldSmKey = pNode->key[0]; int i = 0, j = 0; for(; j < pNode->keyNum; j++){ if(pNode->key[j] != deleteKey){ pNode->key[i] = pNode->key[j]; pNode->dataAddr[i] = pNode->dataAddr[j]; i++; } } if(pNode->key[0] != oldSmKey){ //如果最小key 发生变化,调整最小key adjustKey(pFather, pNode->key[0], sub_idx); } pNode->keyNum--; /* 执行合并操作 */ if(sub_idx == pFather->keyNum-1){ //如果是最右的孩子,就合并到左兄弟去 BPlusTreeNode* pLeftBrother = pFather->subTree[sub_idx-1]; int i = pLeftBrother->keyNum, j = 0; for(; j < pNode->keyNum; j++){ pLeftBrother->key[i] = pNode->key[j]; pLeftBrother->dataAddr[i] = pNode->dataAddr[j]; i++; } pLeftBrother->keyNum = i; pFather->keyNum--; pFather->key[pFather->keyNum] = 0; pFather->subTree[pFather->keyNum] = NULL; free(pNode); pNode = NULL; } else{ // 把右兄弟合并过来比较方便,不用关心最小key的问题 BPlusTreeNode* pRightBrother = pFather->subTree[sub_idx+1]; int i = pNode->keyNum, j = 0; for(; j < pRightBrother->keyNum; j++){ pNode->key[i] = pRightBrother->key[j]; pNode->dataAddr[i] = pRightBrother->dataAddr[j]; i++; } pNode->keyNum = i; /* father的sub_idx+1后的key 和subTree指针前移 */ moveProcess(pFather->key, sub_idx+1, pFather->keyNum); moveProcess(pFather->subTree, sub_idx+1, pFather->keyNum); pFather->keyNum--; pFather->key[pFather->keyNum] = 0; pFather->subTree[pFather->keyNum] = NULL; free(pRightBrother); pRightBrother = NULL; } /* 合并完后判断父节点的key 个数 */ if(pFather->keyNum < 2){ // case 2.2 mergeOrRotate(pFather); } // case 2.1 合并后父节点的key个数任然>= 2则直接结束 return;}/***************************************************************************(1) 如果叶子节点的key 个数大于2,则直接删除即可。(2) 如果不大于2个,则看看其左(右)兄弟(如果存在)是否富裕 case 1: 如果富裕则借一个key, 再删除deleteKey. case 2: 如果兄弟节点都不富裕,则删除deleteKey 后将其和左(右) 节点进行合并 case 2.1: 如果合并后父节点任然富裕,则结束 case 2.2: 如果合并后父节点的key 个数小于2则递归往上继续 进行合并操作*********************************************************************************/void deleteKey(BPlusTreeNode* pCur, int deleteKey){ if(!pCur) return; int sub_idx = 0; /* 一直找到叶子节点 */ BPlusTreeNode* pDeleteLeaf = pCur; while(pDeleteLeaf->isLeaf == false) { for(sub_idx = pDeleteLeaf->keyNum - 1; sub_idx >= 0; sub_idx--){ if(deleteKey >= pDeleteLeaf->key[sub_idx]) break; } if(sub_idx < 0){ cout << deleteKey << " 不存在" << endl; return; } pDeleteLeaf = pDeleteLeaf->subTree[sub_idx]; } if(pDeleteLeaf->keyNum > 2){ /* 如果叶子节点的key 个数大于2 直接删除 */ int i = 0, j = 0; int oldSmKey = pDeleteLeaf->key[0]; for(; i < pDeleteLeaf->keyNum; i++) { if(pDeleteLeaf->key[i] != deleteKey){ pDeleteLeaf->key[j] = pDeleteLeaf->key[i]; pDeleteLeaf->dataAddr[j] = pDeleteLeaf->dataAddr[i]; j++; } } if(j == pDeleteLeaf->keyNum){ cout << deleteKey << " 未找到!!!!!" << endl;return; } pDeleteLeaf->key[j] = 0; pDeleteLeaf->dataAddr[j] = NULL; pDeleteLeaf->keyNum--; if(pDeleteLeaf->key[0] != oldSmKey) adjustKey(pDeleteLeaf->father, pDeleteLeaf->key[0], sub_idx); } else{ BPlusTreeNode* pFather = pDeleteLeaf->father; bool isLeft = false; if(checkBrotherIsRich(pDeleteLeaf, sub_idx, &isLeft)){ // case 1 如果兄弟节点富裕 key > 2 if(isLeft){ // 如果富裕的是左兄弟 BPlusTreeNode* pLeftBrother = pFather->subTree[sub_idx-1]; int n = pLeftBrother->keyNum; int borrowKey = pLeftBrother->key[n-1]; //借用的key void* addrTmp = pLeftBrother->dataAddr[n-1]; pFather->key[sub_idx] = borrowKey; // 因为是左兄弟,sub_idx不可能是0,所以没必要向上调整最小key pLeftBrother->key[n-1] = 0; pLeftBrother->dataAddr[n-1] = NULL; pLeftBrother->keyNum--; //兄弟的key个数减一 /* 删除deleteKey */ int i = 1, j = 0; for(; j < pDeleteLeaf->keyNum; j++){ if(pDeleteLeaf->key[j] != deleteKey){ pDeleteLeaf->key[i] = pDeleteLeaf->key[j]; pDeleteLeaf->dataAddr[i] = pDeleteLeaf->dataAddr[j]; i++; } } pDeleteLeaf->key[0] = borrowKey; pDeleteLeaf->dataAddr[0] = addrTmp; }else{ // 如果富裕的是右兄弟 BPlusTreeNode* pRightBrother = pFather->subTree[sub_idx+1]; int borrowKey = pRightBrother->key[0]; //借用的key void* addrTmp = pRightBrother->dataAddr[0]; pFather->key[sub_idx+1] = pRightBrother->key[1]; int oldSmKey = pDeleteLeaf->key[0]; moveProcess(pRightBrother->key, 0, pRightBrother->keyNum); //key 前移 moveProcess(pRightBrother->dataAddr, 0, pRightBrother->keyNum); pRightBrother->keyNum--; //兄弟的key个数减一 /* 删除deleteKey */ int i = 0, j = 0; for(; j < pDeleteLeaf->keyNum; j++){ if(pDeleteLeaf->key[j] != deleteKey){ pDeleteLeaf->key[i] = pDeleteLeaf->key[j]; pDeleteLeaf->dataAddr[i] = pDeleteLeaf->dataAddr[j]; i++; } } pDeleteLeaf->key[i] = borrowKey; pDeleteLeaf->dataAddr[i] = addrTmp; if(pDeleteLeaf->key[0] != oldSmKey){ //如果最小key 发生变化,调整最小key adjustKey(pFather, pDeleteLeaf->key[0], sub_idx); } } } else{ // case 2 如果兄弟节点不富裕 key <= 2 leafMergeAndDelete(pDeleteLeaf, sub_idx, deleteKey); } } return;}int main(){ BPlusTreeNode* pRoot; pRoot = create_BPlusTree(peopleInfoTable, 20); /* M = 4 的B+树建完后是这样的: 4f 5f 6c / | \ 4f 52 58 5b 5f 64 6c 70 / | | \ / \ / \ 4f 50 51 52 57 58 59 5b 5d 5f 63 64 66 69 6b 6c 6d 70 73 76 */ DPSearch(pRoot); cout << endl; searchInfoByName(pRoot, "沈东镇"); searchInfoByName(pRoot, "杨大勇"); searchInfoByName(pRoot, "李正"); searchInfoByName(pRoot, "赵国"); int key = nameToKey("沈东镇"); cout << "删除key = 0x" << hex << key << endl; deleteKey(pRoot, key); DPSearch(pRoot); cout << endl; /* 删除0x5f 后: 4f 63 6c / | \ 4f 52 58 5b 63 66 6c 70 / | | \ / \ / \ 4f 50 51 52 57 58 59 5b 5d 63 64 66 69 6b 6c 6d 70 73 76 */ searchInfoByName(pRoot, "沈东镇"); key = nameToKey("杨大勇"); cout << "删除key = 0x" << hex << key << endl; deleteKey(pRoot, key); DPSearch(pRoot); cout << endl; /* 删除0x5b 后: 4f 63 6c / | \ 4f 52 58 63 66 6c 70 / | | / \ / \ 4f 50 51 52 57 58 59 5d 63 64 66 69 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x52); cout << "删除key = 0x52" << endl; DPSearch(pRoot); cout << endl; /* 删除0x52 后: 4f 63 6c / | \ 4f 51 58 63 66 6c 70 / | | / \ / \ 4f 50 51 57 58 59 5d 63 64 66 69 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x64); cout << "删除key = 0x64" << endl; DPSearch(pRoot); cout << endl; /* 删除0x64 后: 4f 63 6c / | \ 4f 51 58 63 69 6c 70 / | | / \ / \ 4f 50 51 57 58 59 5d 63 66 69 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x63); cout << "删除key = 0x63" << endl; DPSearch(pRoot); cout << endl; /* 删除0x63 后: (1) 合并: 4f 63 6c / | \ 4f 51 58 66 6c 70 / | | | / \ 4f 50 51 57 58 59 5d 66 69 6b 6c 6d 70 73 76 (2) 旋转: 4f 58 6c / | \ 4f 51 58 66 6c 70 / \ / \ / \ 4f 50 51 57 58 59 5d 66 69 6b 6c 6d 70 73 76 */deleteKey(pRoot, 0x4f);cout << "删除key = 0x4f" << endl;DPSearch(pRoot);cout << endl; /* 删除0x4f 后: (1) 合并: 4f 58 6c / | \ 50 58 66 6c 70 | / \ / \ 50 51 57 58 59 5d 66 69 6b 6c 6d 70 73 76 (2) 合并: 50 6c / \ 50 58 66 6c 70 / | \ / \ 50 51 57 58 59 5d 66 69 6b 6c 6d 70 73 76 */deleteKey(pRoot, 0x50);cout << "删除key = 0x50" << endl;DPSearch(pRoot);cout << endl;/* 删除0x50后: 51 6c / \ 51 58 66 6c 70 / | \ / \ 51 57 58 59 5d 66 69 6b 6c 6d 70 73 76 */deleteKey(pRoot, 0x66);cout << "删除key = 0x66" << endl;DPSearch(pRoot);cout << endl;/* 删除0x66后: 51 6c / \ 51 58 69 6c 70 / | \ / \ 51 57 58 59 5d 69 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x69);cout << "删除key = 0x69" << endl;DPSearch(pRoot);cout << endl;/* 删除0x69后: 51 6c / \ 51 58 5d 6c 70 / | \ / \ 51 57 58 59 5d 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x5d);cout << "删除key = 0x5d" << endl;DPSearch(pRoot);cout << endl;/* 删除0x5d后: 51 6c / \ 51 58 6c 70 / \ / \ 51 57 58 59 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x57);cout << "删除key = 0x57" << endl;DPSearch(pRoot);cout << endl;/* 删除0x57后: 51 6c / \ 51 59 6c 70 / \ / \ 51 58 59 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x58);cout << "删除key = 0x58" << endl;DPSearch(pRoot);cout << endl;/* 删除0x58后: 51 6c 70 / | \ 51 59 6b 6c 6d 70 73 76 */ deleteKey(pRoot, 0x6d);cout << "删除key = 0x6d" << endl;DPSearch(pRoot);cout << endl;/* 删除0x6d后: 51 6b 70 / | \ 51 59 6b 6c 70 73 76 */deleteKey(pRoot, 0x6b);cout << "删除key = 0x6b" << endl;DPSearch(pRoot);cout << endl;/* 删除0x6b后: 51 6c 73 / | \ 51 59 6c 70 73 76 */deleteKey(pRoot, 0x76);cout << "删除key = 0x76" << endl;DPSearch(pRoot);cout << endl;/* 删除0x76后: 51 6c / \ 51 59 6c 70 73 */deleteKey(pRoot, 0x51);cout << "删除key = 0x51" << endl;DPSearch(pRoot);cout << endl;/* 删除0x51后: 59 70 / \ 59 6c 70 73 */deleteKey(pRoot, 0x6c);cout << "删除key = 0x6c" << endl;DPSearch(pRoot);cout << endl;/* 删除0x6c后: 59 70 73 */ return 0;}
运行结果:
0 0
- 学习笔记:B+树模拟数据库索引查找
- 学习笔记-B树,B+树及数据库索引
- 数据库索引 - B树索引
- 数据库索引--B树
- 数据库索引,B+树
- 数据库索引,B+树
- 数据库索引学习笔记
- B树和数据库索引
- B+树与数据库索引
- 《Oracle编程艺术》学习笔记(30)-B*树索引
- 数据库索引--B树/B+树
- 数据库索引、B树、B+树
- 数据库索引B-树和B+树
- 二分查找到B+树索引原理
- 查找数据结构及Mysql数据库索引原理(B-/+Tree)
- 【学习笔记----数据结构23-线性索引查找】
- B树索引学习总结。
- 学习笔记--mysql索引(二) B树索引的介绍和限制,好索引的标准
- 判断IP是否能够ping成功
- Technical Artist的不归路 —— 费茨定律(Fitts's Law)在UI设计中的使用
- C#/VB.net 与本菜鸡一起摸索用图像引擎做游戏
- 防不胜防
- VRRP
- 学习笔记:B+树模拟数据库索引查找
- Java容器类源码-ArrayList的最全的源码分析
- CSS:display基本介绍
- centos 7.0 环境 php-fpm nginx
- UITableViewDataSource 和 UITableViewDelegate协议中常用方法
- <hdoj2544>最短路
- linux挂载usb
- 循环不变式
- 使用RequestDispatcher跳转页面后,JS与CSS样式都不见了的解决方法