二叉搜尋樹的查詢、插入、刪除操作
對於查詢和插入操作相對來說比較簡單,刪除操作則需要考慮的情況較多。
比如有以下些情況,可能有些可以合併,但是我沒想到更好的方法,因此程式碼裡有一堆if else,雖然我不喜歡寫這樣的程式碼,但也沒找到更好的方法。
1. 考慮是否是空樹、或者需要刪除的結點不在樹中。
2. 考慮整棵樹只有一個結點,刪除後需要修改入參,將整棵樹置空。
3. 考慮刪除的結點是葉子結點。
4. 待刪除的結點只有左子樹,或者只有右子樹。
5.待刪除的結點有左右子樹。
下面是我的程式碼,簡單測試過不同的用例,沒什麼問題,但是由於一堆if else讓我很不放心,還有問題也說不定。
//bsearchtree.h
#include <stdio.h>
typedef struct Item{
int m_item;
/**/
}Item;
typedef struct Node{
int key;
Item item;
}Node;
typedef struct Tree{
Node node;
struct Tree * lchild;
struct Tree * rchild;
}Tree;
typedef struct Tree * TreePointer;
const Tree * mybsearch(const Tree * tree, int key);
int binsert(TreePointer * ptree, const Node * nd);
int bdelete(TreePointer * ptree, int key);
void threeWayJoin(Tree * small, Tree * mid, Tree * big);
void twoWayJoin(Tree * small, Tree * big);
void split(Tree * tree, int k, Tree * small, Tree * mid, Tree * big);
void show(TreePointer tree);
//bsertchtree.c
#include "bsearchtree.h"
#include <stdlib.h>
const Tree * mybsearch(const Tree * tree, int key)
{
if(NULL == tree)
{
return NULL;
}
if(key == tree->node.key)
return tree;
if(key > tree->node.key)
return mybsearch(tree->rchild, key);
else
return mybsearch(tree->lchild, key);
}
/*迴圈實現
{
while(tree)
{
if(key == tree->node.key)
return tree;
if(key > tree->node.key)
{
tree = tree->rchild;
}
else
{
tree = tree->lchild;
}
}
return NULL;
}
*/
int binsert(TreePointer * ptree, const Node * nd)
{
Tree * current = *ptree;
Tree * prev = NULL;
Tree * pnew;
while(current)
{
if(nd->key == current->node.key)
{
return 0;
}
prev = current;
if(nd->key > current->node.key)
current = current->rchild;
else
current = current->lchild;
}
pnew = (Tree *)malloc(sizeof(Tree));
pnew->node = *nd;
pnew->lchild = pnew->rchild = NULL;
if(prev)
{
if(nd->key > prev->node.key)
prev->rchild = pnew;
else
prev->lchild = pnew;
}
else
*ptree = pnew;
return 1;
}
int bdelete(TreePointer * ptree, int key)
{
Tree * current = *ptree;
Tree * prev = NULL;
int flag = 0;//找到關鍵字為1, 沒找到為0
/*查詢樹中是否存在關鍵字項key, current 指向含key的結點, prev指向其前驅結點*/
while(current)
{
if(key == current->node.key)
{
flag = 1;
break;
}
prev = current;
if(key > current->node.key)
current = current->rchild;
else
current = current->lchild;
}
//沒有查詢到需要刪除的結點
if(!flag)
{
return 0;
}
//整棵樹只有一個結點
if((*ptree)->lchild == NULL && (*ptree)->rchild == NULL)
{
free(*ptree);
*ptree = NULL;
return 1;
}
//待刪除的結點是葉子結點
if(current->lchild == NULL && current->rchild == NULL)
{
if(prev->lchild == current)
prev->lchild = NULL;
else
prev->rchild = NULL;
}
//待刪除的結點只有一個右子結點
else if(current->lchild == NULL)
{
if(prev->lchild == current)//前驅結點的左指標指向當前結點
prev->lchild = current->rchild;
else //前驅結點的右指標指向當前結點
prev->rchild = current->rchild;
}
//待刪除的結點只有一個左子結點
else if(current->rchild == NULL)
{
if(prev->lchild == current)
prev->lchild = current->lchild;
else
prev->rchild = current->lchild;
}
//待刪除的結點有2個子結點
else
{
//尋找左子樹中key最大的結點, save儲存其前驅結點
Tree * save = current;
Tree * temp = current->lchild;
while(temp->rchild)
{
save = temp;
temp = temp->rchild;
}
if(save == current)
save->lchild = temp->lchild;
else
save->rchild = temp->lchild;
current->node = temp->node;
current = temp;
}
free(current);
return 1;
}
void threeWayJoin(Tree * small, Tree * mid, Tree * big);
void twoWayJoin(Tree * small, Tree * big);
void split(Tree * tree, int k, Tree * small, Tree * mid, Tree * big);
void show(TreePointer tree)
{
if(tree)
{
printf("key = %d, data = %d\n", tree->node.key, tree->node.item.m_item);
show(tree->lchild);
show(tree->rchild);
}
}
//test.c ,測試的資料可以自己修改
#include "bsearchtree.h"
#include <stdlib.h>
#include <time.h>
int main(void)
{
int i;
Node node;
TreePointer tree;
srand(time(NULL));
tree = NULL;
/*
for(i =0; i < 10; i++)
{
node.key = rand() % 10;
node.item.m_item = i;
binsert(&tree, &node);
printf("insert: key = %d, data = %d\n", node.key, node.item.m_item);
}
*/
node.key = 1;
node.item.m_item = 0;
binsert(&tree, &node);
node.key = 8;
binsert(&tree, &node);
node.key = 3;
binsert(&tree, &node);
node.key = 2;
binsert(&tree, &node);
node.key = 9;
binsert(&tree, &node);
printf("after insert: \n");
show(tree);
printf("after delete: \n");
bdelete(&tree, 8);
show(tree);
return 0;
}