B树插入向一个已经有M项的节点添加元素,则在分裂该节点以前要执行搜索具有少于M个儿子的兄弟的工作

数据结构与算法分析——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;
}



你可能感兴趣的:(B树插入向一个已经有M项的节点添加元素,则在分裂该节点以前要执行搜索具有少于M个儿子的兄弟的工作)