数据结构与算法分析——c语言描述 练习4.37c 答案
不是很难。反而测试的时候爆出了一个删除的bug。。。原来是树叶删除后剩下两个儿子没有更新索引。
再爆出一个删除bug,不过这个bug是调试原来发的三阶b树才发现的。还是索引的问题,问题是移动儿子指针再更新兄弟的索引,sonbranch已经不是指向兄弟了。互换两行代码顺序即可。虽然这个bug很简单。但是找出来可是。。。。。。。。。一个中午和半个下午又没了。。。。
#include"btree.h" #include<stdlib.h> #include"fatal.h" struct BtreeNode; #define M 3 struct BtreeNode { int type; int sonNum;//儿子数量,或当前拥有数据的数量(最底层) PtrToNode PtrToSon[M]; ElementType elem[M]; }; static int binarySearch(PtrToNode bottomNode, ElementType X) {//对分搜索 if (bottomNode->type != 2) Error("ERROR!..."); ElementType* arr = bottomNode->elem; int n = bottomNode->sonNum; if (n > 0) { int low = 0; int high = n - 1; while (low <= high) { int mid = (high + low) / 2; if (X < arr[mid]) { high = mid - 1; } else if (X > arr[mid]) { low = mid + 1; } else return mid; } return -1; } return -1; } static int getSonBranch(PtrToNode Node, ElementType X) { ElementType* arr = Node->elem; int n = Node->sonNum; if (n == 1) return 0; else if (n == 2) { if (X < arr[0]) return 0; else return 1; } else if (n >= 2) { int low = 0; int high = n - 1 - 1;//第一个分支没有索引 while (low <= high) { int mid = (high + low) / 2; if (X < arr[mid]) { high = mid - 1; } else if (X > arr[mid]) { low = mid + 1; } else return mid + 1;//第一个分支没有索引 } return high + 1;//退出循环,此时high在左,low在右,X位于high和low的值之间 } else { Error("GET SON BRANCH ERROR"); } } static void binaryInsert(ElementType arr[], int n, ElementType X) { int low = 0; int high = n - 1; while (low <= high) { int mid = (low + high) / 2; if (arr[mid] < X) { low = mid + 1; } else if (arr[mid] > X) high = mid - 1; } while (arr[low] < X&& low < n) { low++; } for (int i = n; i > low; i--) { arr[i] = arr[i - 1]; } arr[low] = X; } static void binaryInsertForBottomNode(PtrToNode bottomNode, ElementType X) {//对分插入 if (bottomNode->type != 2) Error("eror!"); ElementType* arr = bottomNode->elem; int n = bottomNode->sonNum; if (n > 0) { binaryInsert(arr, n, X); } else arr[0] = X; bottomNode->sonNum++; } static PtrToNode allocNode(int type) {//0为内部节点 1为叶子 2为底层节点 PtrToNode p = malloc(sizeof(struct BtreeNode)); if (p == NULL) Error("OUT OF SPACE!!"); p->type = type; p->sonNum = 0; return p; } static void updateIndex(PtrToNode p) { if (p->sonNum >= 2) { for (int i = 0; i < p->sonNum - 1; i++) { PtrToNode son = p->PtrToSon[i + 1]; while (son->type != 2) { son = son->PtrToSon[0]; } p->elem[i] = son->elem[0]; } } } static PtrToNode insertAndSplitBottomNode(PtrToNode b1, ElementType X) { if (b1->sonNum != 3) Error("ERROR!"); PtrToNode b2 = allocNode(2); ElementType tempElem[4]; for (int i = 0; i < 3; i++) tempElem[i] = b1->elem[i]; binaryInsert(tempElem, 3, X); for (int i = 0; i < 2; i++) b1->elem[i] = tempElem[i]; for (int i = 0; i < 2; i++) b2->elem[i] = tempElem[i + 2]; b1->sonNum = b2->sonNum = 2; return b2; } static PtrToNode split(Btree father, PtrToNode newSon, int sonBranch) { PtrToNode allSon[4]; int i, j; for (i = 0, j = 0; j <= sonBranch; i++, j++) allSon[i] = father->PtrToSon[j]; allSon[i++] = newSon; for (; j < father->sonNum; i++, j++) allSon[i] = father->PtrToSon[j]; PtrToNode newFater = allocNode(father->type); father->sonNum = 2; father->PtrToSon[0] = allSon[0]; father->PtrToSon[1] = allSon[1]; updateIndex(father); newFater->sonNum = 2; newFater->PtrToSon[0] = allSon[2]; newFater->PtrToSon[1] = allSon[3]; updateIndex(newFater); return newFater; } static void insertPtrToSon(PtrToNode father, PtrToNode newSon, int sonBranch) { if (father->sonNum == 0) { father->PtrToSon[0] = newSon; } else { int i; for (i = father->sonNum; i > sonBranch + 1; i--) { father->PtrToSon[i] = father->PtrToSon[i - 1]; } father->PtrToSon[sonBranch + 1] = newSon; } father->sonNum++; } Btree createBtree() { Btree t = malloc(sizeof(struct BtreeNode)); if (t == NULL) Error("OUT OF MEMORY!"); t->sonNum = 0; t->type = 1;//空树,根节点也是树叶 return t; } void makeEmpty(Btree t) { if (t->type) { for (int i = 0; i < t->sonNum; i++) free(t->PtrToSon[i]); free(t); } else { for (int i = 0; i < t->sonNum; i++) { makeEmpty(t->PtrToSon[i]); } free(t); } } PtrToNode find(ElementType X, Btree t) { if (t->type == 0) {//内部节点 int p = getSonBranch(t, X); return find(X, t->PtrToSon[p]); } else { int p; if (t->sonNum == 0)//刚创建树的时候,空 return NULL; else if (t->sonNum == 1) { p = binarySearch(t->PtrToSon[0], X); if (p == -1) return NULL; else return t->PtrToSon[0]; } else { p = getSonBranch(t, X);//选择儿子分支 int tempCursor = binarySearch(t->PtrToSon[p], X);//在最底层中查找 if (tempCursor == -1) return NULL; return t->PtrToSon[p]; } } } static void insertElem_LeafEmpty(ElementType X, Btree t) { //leafAddNewSon(t, 0); PtrToNode newSon = allocNode(2); binaryInsertForBottomNode(newSon, X); insertPtrToSon(t, newSon, 0); } static void insertElem_LeafSonNotFull(ElementType X, Btree t, int sonChoice) { binaryInsertForBottomNode(t->PtrToSon[sonChoice], X); updateIndex(t); } static Btree insert_internal(ElementType X, Btree t); static void insertElem_LeafNotFull_LeafSonFull(ElementType X, Btree t, int sonBranch) { PtrToNode newSon = insertAndSplitBottomNode(t->PtrToSon[sonBranch], X); insertPtrToSon(t, newSon, sonBranch); updateIndex(t); } static PtrToNode insertElem_LeafFull_LeafSonFull(ElementType X, Btree t, int sonBranch) { PtrToNode newSon = insertAndSplitBottomNode(t->PtrToSon[sonBranch], X); PtrToNode newFather = split(t, newSon, sonBranch); return newFather; } static Btree insert_internal(ElementType X, Btree t) { if (t->type == 0) {//非叶子 int sonBranch = getSonBranch(t, X); PtrToNode newSon = insert_internal(X, t->PtrToSon[sonBranch]); if (newSon) { if (t->sonNum < M) { insertPtrToSon(t, newSon, sonBranch); updateIndex(t); return NULL; } else { PtrToNode newfather = split(t, newSon, sonBranch); return newfather; } } else return NULL; } else if (t->type == 1) {//叶子 if (t->sonNum == 0) { insertElem_LeafEmpty(X, t); return NULL; } else { int sonBranch = getSonBranch(t, X);//选择儿子分支 int XCursor = binarySearch(t->PtrToSon[sonBranch], X);//在儿子中查找 if (XCursor == -1) {//不存在X if (t->PtrToSon[sonBranch]->sonNum < M) {//叶子的儿子数量未满 insertElem_LeafSonNotFull(X, t, sonBranch); return NULL; } else if (sonBranch > 0 && t->PtrToSon[sonBranch - 1]->sonNum < M) {//左兄弟未满 t->PtrToSon[sonBranch - 1]->elem[M - 1] = t->PtrToSon[sonBranch]->elem[0]; t->PtrToSon[sonBranch - 1]->sonNum++; for (int i = 0; i < M - 1; i++) { t->PtrToSon[sonBranch]->elem[i] = t->PtrToSon[sonBranch]->elem[i + 1]; } t->PtrToSon[sonBranch]->sonNum--; binaryInsertForBottomNode(t->PtrToSon[sonBranch], X); updateIndex(t); return NULL; } else if (sonBranch + 1 < t->sonNum&& t->PtrToSon[sonBranch + 1]->sonNum < M) {//右兄弟未满 binaryInsertForBottomNode(t->PtrToSon[sonBranch + 1], t->PtrToSon[sonBranch]->elem[M - 1]); t->PtrToSon[sonBranch]->sonNum--; binaryInsertForBottomNode(t->PtrToSon[sonBranch], X); updateIndex(t); return NULL; } else if (t->sonNum < M && t->PtrToSon[sonBranch]->sonNum == M) {//父亲未满,儿子满,分裂 insertElem_LeafNotFull_LeafSonFull(X, t, sonBranch); return NULL; } else {//父亲满,儿子满 PtrToNode newfather = insertElem_LeafFull_LeafSonFull(X, t, sonBranch); return newfather; } } else return NULL;//已存在X } } else { Error("type error"); } } Btree insert(ElementType X, Btree t) { PtrToNode p = insert_internal(X, t); if (p == NULL) return t; else { PtrToNode newRoot = allocNode(0); insertPtrToSon(newRoot, t, 0); insertPtrToSon(newRoot, p, 0); updateIndex(newRoot); return newRoot; } } void Dir(Btree t) { if (t->type == 0) { for (int i = 0; i < t->sonNum; i++) Dir(t->PtrToSon[i]); } else if (t->type == 1) { printf("\n"); for (int i = 0; i < t->sonNum; i++) { for (int j = 0; j < t->PtrToSon[i]->sonNum; j++) { printf("%d ", t->PtrToSon[i]->elem[j]); } printf(" "); } } } static void deleteAndFreePtrToSon(PtrToNode father, int sonBranch) { free(father->PtrToSon[sonBranch]); for (int i = sonBranch; i < father->sonNum - 1; i++) { father->PtrToSon[i] = father->PtrToSon[i + 1]; } father->sonNum--; } static void deletePtrToSon(PtrToNode father, int sonBranch) { for (int i = sonBranch; i < father->sonNum - 1; i++) { father->PtrToSon[i] = father->PtrToSon[i + 1]; } father->sonNum--; } static void binaryDeleteForBottomNode(PtrToNode bottomNode, ElementType X) { int p = binarySearch(bottomNode, X); if (p != -1) { for (int i = p; i < bottomNode->sonNum - 1; i++) { bottomNode->elem[i] = bottomNode->elem[i + 1]; } bottomNode->sonNum--; } } static int delete_internal(ElementType X, Btree t) {//返回类型0表示儿子够,1表示儿子不够 if (t->type == 0) {//内部节点 int p = getSonBranch(t, X); int isSon_NotEnough_grandson = delete_internal(X, t->PtrToSon[p]); if (isSon_NotEnough_grandson == 0) return 0; else {//// int brother; if (p + 1 < t->sonNum) { brother = p + 1; } else { brother = p - 1; } if (t->PtrToSon[brother]->sonNum == 2) { if (p < brother) { insertPtrToSon(t->PtrToSon[brother], t->PtrToSon[p]->PtrToSon[0], -1); } else insertPtrToSon(t->PtrToSon[brother], t->PtrToSon[p]->PtrToSon[0], 1); updateIndex(t->PtrToSon[brother]);//这个顺序一定要在前面,因为deleteAndFreePtrToSon移动了儿子指针,所以要先更新 deleteAndFreePtrToSon(t, p); updateIndex(t); return t->sonNum == 1; } else if (t->PtrToSon[brother]->sonNum == 3) { if (p < brother) { insertPtrToSon(t->PtrToSon[p], t->PtrToSon[brother]->PtrToSon[0], 0); deletePtrToSon(t->PtrToSon[brother], 0); } else { insertPtrToSon(t->PtrToSon[p], t->PtrToSon[brother]->PtrToSon[2], -1); deletePtrToSon(t->PtrToSon[brother], 2); } updateIndex(t->PtrToSon[p]); updateIndex(t->PtrToSon[brother]); updateIndex(t); return 0; } else { Error("what the hell?"); return 0; } } } else if (t->type == 1) {//叶子 int p; if (t->sonNum == 0)//刚创建树的时候,空 return 0; if (t->sonNum == 1) { p = 0; } else { p = getSonBranch(t, X);//选择儿子分支 } binaryDeleteForBottomNode(t->PtrToSon[p], X); if (t->PtrToSon[p]->sonNum == 0) { deleteAndFreePtrToSon(t, p); return 0; } else if (t->PtrToSon[p]->sonNum == 1) { int brother; if (p > 0) { brother = p - 1; } else if (p + 1 < t->sonNum) { brother = p + 1; } else {//只有一个儿子,无兄弟 return 0; } if (t->PtrToSon[brother]->sonNum == 3) { if (brother < p) { t->PtrToSon[p]->elem[1] = t->PtrToSon[p]->elem[0]; t->PtrToSon[p]->elem[0] = t->PtrToSon[brother]->elem[2]; t->PtrToSon[p]->sonNum++; t->PtrToSon[brother]->sonNum--; } else { t->PtrToSon[p]->elem[1] = t->PtrToSon[brother]->elem[0]; for (int i = 0; i < 2; i++) { t->PtrToSon[brother]->elem[i] = t->PtrToSon[brother]->elem[i + 1]; } t->PtrToSon[p]->sonNum++; t->PtrToSon[brother]->sonNum--; } updateIndex(t); return 0; } else if (t->PtrToSon[brother]->sonNum == 2) { binaryInsertForBottomNode(t->PtrToSon[brother], t->PtrToSon[p]->elem[0]); deleteAndFreePtrToSon(t, p); updateIndex(t); return t->sonNum == 1; } else { Error("what the hell?"); return 0; } } else//底层节点关键字数目为2 return 0; } else { Error("what the hell?"); return 0; } } Btree Delete(ElementType X, Btree t) { if (delete_internal(X, t)) { if (t->type == 0) { Btree newRoot = t->PtrToSon[0]; free(t); return newRoot; } } updateIndex(t); return t; }