前言
二叉搜索樹是什麼
二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹。
基本操作
插入
遞歸
int BSTreeInsertR(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
if (*tree == NULL)
{
*tree = BuyBSTreeNode(x);
return 1;
}
if ((*tree)->_data > x)
return BSTreeInsertR(&(*tree)->_left, x);
else if ((*tree)->_data < x)
return BSTreeInsertR(&(*tree)->_right, x);
else
return 0;
}
非遞歸
//搜索二叉樹左子樹的數據小於根結點,右子樹的的數據大於根節點 並且不能插入裏面已經有的數據
int BSTreeInsert(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
BSTreeNode* parent =NULL;
BSTreeNode* cur = *tree;
if (cur == NULL)
{
*tree = BuyBSTreeNode(x);
//插入成功
return 1;
}
while (cur)
{
if (x < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (x>cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
//遇到相同的數據插入失敗
return 0;
}
}
if (x < parent->_data)
{
parent->_left = BuyBSTreeNode(x);
}
else
{
parent->_right = BuyBSTreeNode(x);
}
return 1;
}
刪除
思路分析:(將要刪除的結點標記爲del)
第一種情況要刪除的結點無左右孩
方法:直接刪除該結點,並讓其父結點從指向它變爲指向空
注意:如果刪除的結點爲根結點,根結點是沒有父結點的,就將根節點的右孩重新定爲新的根節點。
第二種情況要刪除的結點有左孩無右孩
方法:讓該結點的父節點的左孩指向該結點的左孩
注意:如果刪除的結點爲根結點,根結點是沒有父結點的,就將根節點的左孩重新定爲新的根節點。
第三種情況要刪除的結點無左孩有右孩
方法:與第一種情況解決方法一樣。
第四種情況要刪除的結點左右孩都存在
方法:找到該結點的右子樹中最左的結點(在此稱它爲repalce),爲什麼要找replace呢,因爲replace是del右子樹中最小的數,然後將replace的數據代替del中的數據,這樣整體依然滿足二叉搜索樹的特性,然後再利用遞歸刪除,刪除replace。
ps:要刪除的結點並不是真的刪除這個結點,而是將它的值替換了。
遞歸
int BSTreeRemoveR(BSTreeNode** tree, BSTDataType x)
{
if (*tree == NULL)
return -1;
if ((*tree)->_data > x)
BSTreeRemoveR(&(*tree)->_left, x);
else if ((*tree)->_data < x)
BSTreeRemove(&(*tree)->_right,x);
else
{
//左爲空右不爲空/爲空
BSTreeNode* del = *tree;
if ((*tree)->_left == NULL)
{
*tree = (*tree)->_right;
free(del);
}
//左不爲空 右爲空
else if ((*tree)->_right == NULL)
{
*tree = (*tree)->_left;
free(del);
}
//左右都不爲空
else
{
//先找右子樹的最左子樹
BSTreeNode* replace = (*tree)->_right;
while (replace->_left)
{
replace = replace->_left;
}
(*tree)->_data = replace->_data;
return BSTreeRemoveR(&(*tree)->_right, replace->_data);
}
return 1;
}
return 0;
}
非遞歸
int BSTreeRemove(BSTreeNode** tree, BSTDataType x)
{
assert(tree);
assert(tree);
BSTreeNode* parent = NULL;
BSTreeNode* cur = *tree;
if (cur == NULL)
return 0;//刪除失敗
while (cur)
{
if (x < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (x>cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
{
//無左孩子有右孩 或者無左孩無右孩
if (cur->_left == NULL)
{
//如果是根結點,特殊處理
if (cur == *tree)
{
*tree = cur->_right;
free(cur);
return 1;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
free(cur);
return 1;//刪除成功
}
}
//有左孩子無右孩
else if (cur->_right == NULL)
{
//如果是根結點,特殊處理
if (cur == *tree)
{
*tree = cur->_left;
free(cur);
return 1;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
free(cur);
return 1;//刪除成功
}
}
//有左孩也有右孩
//採用替換的方法
//找到該結點底下右結點中最左的孩子與其交換 因爲其右結點中最左的孩子比該結點左邊的結點都要大,但比該結點右邊結點都要小,所以要找到它
else
{
BSTreeNode* cur1 = cur->_right;
while (cur1->_left)
{
cur1 = cur1->_left;
}
//找到後開始交換值
cur->_data = cur1->_data;
return BSTreeRemove(&cur->_right, cur1->_data);//遞歸刪除
}
}
}
return 0;
}