二叉排序树(BST)(二叉搜索树,二叉查找树):
或者是一棵空树,或者是具有下列性质的二叉树:
1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3. 它的左、右子树也分别为二叉排序树。
//定义树的结构体
typedef struct BiNode {
int data;
struct BiNode *lchild, *rchild;
}BiTNode;
void InitBST(BiTNode *root)
{
if (root == NULL)return;
//测试用例
BiTNode *n[10];
for (int i = 0; i < 10; i++)
{
n[i] = (BiTNode*)malloc(sizeof(BiTNode));
n[i]->data = i;
}
root->lchild = n[3];
root->rchild = n[7];
n[3]->lchild = n[1];
n[3]->rchild = n[4];
n[7]->lchild = n[6];
n[7]->rchild = n[9];
n[1]->rchild = NULL;
n[1]->lchild = NULL;
n[4]->rchild = NULL;
n[4]->lchild = NULL;
n[6]->rchild = NULL;
n[6]->lchild = NULL;
n[9]->rchild = NULL;
n[9]->lchild = NULL;
}
//排序树查找算法
/*
1.若root是空树,则搜索失败,否则:
2.若key等于root的的数据域之值,则查找成功;否则:
3.若key小于root的数据域之值,则搜索root左子树;否则:
4.查找右子树。
参数lastT表示最后一次搜索的到的结点(用在下面Insert功能中)
*/
BiTNode *SearchBST(BiTNode *root, int key,BiTNode **lastT)
{
if (root == NULL)
{
return NULL;
}
else if (root->data == key)
{
return root;
}
else if (root->data > key)
{
*lastT = root;//保存上一次遍历的值结点
return SearchBST(root->lchild, key, lastT);
}
else
{
*lastT = root;//保存上一次遍历的结点
return SearchBST(root->rchild, key, lastT);
}
}
//当存在已插入的元素时返回0,否则返回1
int InsertBST(BiTNode *root, int key)
{
BiTNode *lastT = NULL;//保存上次搜索最后一次遍历的元素(一般用在未找到时,因为只有未找到给定元素才进行插入操作)
if (!SearchBST(root, key, &lastT))//如果未找到元素
{
BiTNode *newNode = (BiTNode*)malloc(sizeof(BiTNode));//为即将要插入的新结点开辟空间
newNode->data = key;
newNode->lchild = newNode->rchild = NULL;
if (lastT->data > key)
{
lastT->lchild = newNode;
}
else
{
lastT->rchild = newNode;
}
return 1;
}
return 0;
}
//删除一个结点
/* 1,若结点为叶子结点,那么直接调整其父结点的指向为空即可。
2,若结点的只有左子树或者右子树不为空(左右子树有一个为空,一个不为空),那么只需要根据要删除的元素在其父节点的位置来判断,
如删除节点只存在左子树,只需把子树重新连接到父节点空出来的位置就可以了。
3,若结点的左右结点都存在,找到被删除节点(DN)的左子树(DNL),该节点(DNL)一直往右走的结点(DNLR)(这个元素是被删除节点左子树中值最大的节点)
移动该节点(DNLR)的值到要删除结点(DN)的位置。然后再删除找到该节点(DNLR)位置即可。
*/
int Delete(BiTNode *node);
int DeleteBST(BiTNode **root, int key)
{
BiTNode *lastptr = NULL;
if ((*root)->data == key)
{
Delete(root);
return 1;
}
else if ((*root)->data < key)
{
DeleteBST(&(*root)->rchild, key);
}
else if ((*root)->data > key)
{
DeleteBST(&(*root)->lchild, key);
}
return 0;
}
int Delete(BiTNode **node)
{
BiTNode *tmp,*tmpleft;
if ((*node)->lchild == NULL)//如果删除结点的左子树为空,只需重接被删除结点的右子树
{
tmp = *node; *node = (*node)->rchild; free(tmp);
}
else if ((*node)->rchild == NULL)//重接左子树
{
tmp = *node; *node = (*node)->lchild; free(tmp);
}
else//左右子树都不为NULL//1.从被删除的结点的左子树找到最大的结点替换被删除的结点。2,将第一步找到的结点的左子树重接到他的父节点位置(找到的那个结点的位置)
{
BiTNode *MaxVal = NULL;
MaxVal = (*node)->lchild;//tmp就是那个被找到的结点,它的val最大
while (MaxVal->rchild != NULL)
{
MaxVal = MaxVal->rchild;
}
tmp = *node;
(*node)->data = MaxVal->data;
Delete(&MaxVal);//删除那个被找到结点的左子树
free(MaxVal);
}
}
注意:
- 以上删除节点时通过二级指针传参修改了父节点对自己的指向,无需在树的结构体中定义该节点的父节点。