二叉搜索树
- 概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
- 结构
typedef int DataType;
typedef struct BSTreeNode {
DataType key;
struct BSTreeNode *left;
struct BSTreeNode *right;
} BSTreeNode;
二叉搜索树的操作
- 插入
在二叉搜索树中插入新元素时,必须先检测该元素是否在树中已经存在。如果已经存在,则不进行插入;否则将新元素加入到搜索停止的地方。
//非递归形式
int BSTreeInsert(BSTreeNode **root, DataType key)
{
BSTreeNode *cur = *root;
BSTreeNode *parent = NULL;
//找到要插入的位置
while(cur != NULL)
{
//值重复,插入失败
if(key == cur->key)
{
return -1;
}
parent = cur;
if(key > cur->key)
{
cur = cur->right;
}
else
{
cur = cur->left;
}
}
//创建节点
BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
node->key = key;
node->left = node->right = NULL;
//空树,直接插入
if(parent == NULL)
{
*root = node;
return 1;
}
if(key < parent->key)
{
parent->left = node;
}
else
{
parent->right = node;
}
return 1;
}
//递归形式
int ReBSTreeInsert(BSTreeNode **root, DataType key)
{
if(*root == NULL)
{
//创建节点
BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
node->key = key;
node->left = node->right = NULL;
*root = node;
return 1;
}
if(key == (*root)->key)
{
//值重复
return -1;
}
if(key < (*root)->key)
{
return ReBSTreeInsert(&(*root)->left, key);
}
else
{
return ReBSTreeInsert(&(*root)->right, key);
}
}
- 查找
思路:
根结点不为空,继续查找,否则返回false
//失败返回-1,成功返回1
//非递归形式
int BSTreeSearch(const BSTreeNode *root, DataType key)
{
BSTreeNode *cur = (BSTreeNode *)root;
while(cur != NULL)
{
if(key == cur->key)
{
return 1;
}
else if(key > cur->key)
{
cur = cur->right;
}
else
{
cur = cur->left;
}
}
return -1;
}
//递归形式
int ReBSTreeSearch(const BSTreeNode *root, DataType key)
{
if(root == NULL)
{
return -1;
}
if(key == root->key)
{
return 1;
}
else if (key > root->key)
{
return ReBSTreeSearch(root->right, key);
}
else
{
return ReBSTreeSearch(root->left, key);
}
}
- 删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回
删除节点可能分为下面四个情况:
- 要删除的节点无孩子节点
- 要删除的节点只有左孩子节点
- 要删除的节点只有右孩子节点
- 要删除的节点既有左孩子又有右孩子
//删除左为空
static void RemoveLeftNULL(DataType key, BSTreeNode *parent, BSTreeNode **root, BSTreeNode *cur)
{
if(parent == NULL)
{
//要删除的就是根结点
*root = cur->right;
}
else
{
if (key < parent->key) {
// cur 是 parent 的 left
parent->left = cur->right;
}
else {
// cur 是 parent 的 right
parent->right = cur->right;
}
}
free(cur);
}
//删除右为空
static void RemoveRightNULL(DataType key, BSTreeNode *parent, BSTreeNode **root, BSTreeNode *cur)
{
if (parent == NULL)
{
// 要删除的就是根结点
*root = cur->left;
}
else
{
if (key < parent->key)
{
// cur 是 parent 的 left
parent->left = cur->left;
}
else
{
// cur 是 parent 的 right
parent->right = cur->left;
}
}
free(cur);
}
//删除左右都不为空
static void RemoveHasLeftAndRight(BSTreeNode *cur)
{
// 找左子树中最大的
BSTreeNode *del = cur->left;
BSTreeNode *delParent = NULL;
while (del->right != NULL)
{
delParent = del;
del = del->right;
}
// del 就是左子树中最大的
cur->key = del->key;
// 删除 del 结点
if (delParent == NULL)
{
// 左孩子中最大的就是 cur 的左孩子
cur->left = del->left;
}
else
{
delParent->right = del->left;
}
free(del);
}
//删除二叉搜索树节点(非递归)
// 找到就删除,返回成功 1
// 没找到删除失败,返回 -1
int BSTreeNodeRemove(BSTreeNode **root, DataType key)
{
// 先查找,后删除
BSTreeNode *cur = *root;
BSTreeNode *parent = NULL;
while (cur != NULL)
{
if (key == cur->key)
{
// 这里找到了,这里是删除的地方
if (cur->left == NULL)
{
// cur 没有左孩子
RemoveLeftNULL(key, parent, root, cur);
}
else if (cur->right == NULL)
{
// cur 没有右孩子
RemoveRightNULL(key, parent, root, cur);
}
else
{
// 左右孩子都不为空
RemoveHasLeftAndRight(cur);
}
return 1;
}
parent = cur;
if (key < cur->key)
{
cur = cur->left;
}
else
{
cur = cur->right;
}
}
return -1;
}
//递归删除
int ReBSTreeNodeRemove(BSTreeNode **root, DataType key)
{
if (*root == NULL)
{
return 0;
}
if (key == (*root)->key)
{
BSTreeNode *del = *root;
if ((*root)->left == NULL)
{
// 1. 要删除的是不是根
// 2. 判断要删除的结点是根的左还是右
*root = (*root)->right;
free(del);
}
else if ((*root)->right == NULL)
{
*root = (*root)->left;
free(del);
}
else
// 左右都不为空
RemoveHasLeftAndRight(*root);
}
return 1;
}
if (key < (*root)->key)
{
return ReBSTreeNodeRemove(&(*root)->left, key);
}
else
{
return ReBSTreeNodeRemove(&(*root)->right, key);
}
}