二叉查找树(二叉搜索树)
定义:
1. 左子树的节点均小于根节点
2. 右子树的节点均不小于根节点
3. 左右子树也满足上面的两个条件
如下图所示:
二叉查找树的查找
1.如果当前节点小于查找值,则去当前节点的左孩子进一步查找
2.如果当前节点大于查找值,则去当前节点的左孩子进一步查找
3.如果当前节点为空或者等于查找值,则返回结果
代码实现:
/*
在root二叉搜索树中搜索值为value的节点
*/
struct Tnode* searchValue(struct Tnode* root,int value){
if(root==NULL){
return NULL;
}
//如果*root节点中的值恰好为value,则直接返回root元素即可
if(root->value==value){
return root;
}else if(root->value<value){
return searchValue(root->right, value);
}else{
return searchValue(root->left, value);
}
}
二叉查找树的插入
1.如果跟节点为空,则将插入值放入该根节点
2.如果插入值小于根节点,则将该值插入到左子树
3.如果插入值不小于根节点,则将该值插入到右子树(重复值如何处理呢?)
代码实现:
/*
在root二叉搜索树中插入值为value的节点
*/
void insertValue(struct Tnode** root,int value){
if(*root==NULL){
*root = (struct Tnode*)malloc(sizeof(struct Tnode));
(*root)->value = value;
(*root)->left = NULL;
(*root)->right = NULL;
return;
}
if((*root)->value<value){
insertValue(&(*root)->right, value);
}else if((*root)->value>value){
insertValue(&(*root)->left, value);
}else{
printf("the same value in the tree : %d \n",value);
}
}
二叉查找树的建立
同上面的插入操作
代码实现:
/*
通过插入元素的方式,创建二叉搜索树
*/
struct Tnode* makeSearchTree(int* arr,int len){
//将元素逐个插入到二叉搜索树中
struct Tnode * root = NULL;
for(int i=0;i<len;i++){
insertValue(&root,arr[i]);
}
return root;
}
二叉查找树的删除
待删除的孩子的三种的情况:
1. 删除叶子节点
直接释放该节点,并且将该节点的父亲指向自己节点的指针设置为null
2. 删除只有一个孩子的节点
直接释放该节点,并且将该节点的父亲指向自己的子树的根节点
3. 删除有两个孩子的节点
直接用当前节点的直接前驱(后继) 替代当前接节点的位置,并将将该前驱(后继)
的子树设置为该前驱父亲的孩子节点
代码实现一:
/*
在root二叉搜索树中删除值为value的节点
1.叶子节点 直接删除
2.单儿子节点,直接将儿子放在父节点的下面
3.双儿子节点,直接找当前节点的直接后继
*/
struct Tnode* deleteValue(struct Tnode* root,struct Tnode* p, int value){
//没有找到需要删除的节点,直接返回NULL
if(root==NULL){
return NULL;
}
//如果root指向的节点,就是需要被删除的对象,则进行删除逻辑操作
if(root->value==value){
if(root->left==NULL && root->right ==NULL){
if(p){
if(p->left==root){
p->left = NULL;
}else{
p->right = NULL;
}
}
}else if(root->left==NULL || root->right ==NULL){
struct Tnode* child;
if(root->left == NULL){
child = root->right;
root->right = NULL;
}else{
child = root->left;
root->left = NULL;
}
if(p){
if(p->left==root){
p->left = child;
}else{
p->right = child;
}
}
}else{
//获取当前节点的直接后继
struct Tnode* tmp = root->right;
struct Tnode* p = root;
while (tmp->left!=NULL) {
p = tmp;
tmp = tmp->left;
}
//如果直接后继,有右子树,则将右子树升级一下;没有,则将直接后继从树中脱离
if(tmp->right!=NULL){
if(p->left==tmp){
p->left = tmp->right;
}else{
p->right = tmp->right;
}
}else{
if(p->left==tmp){
p->left = NULL;
}else{
p->right = NULL;
}
}
tmp->left = NULL;
p = NULL;
//将tmp左右子树进行赋值
tmp->left = root->left;
tmp->right = root->right;
if(p){
if(p->left==root){
p->left = tmp;
}else{
p->right = tmp;
}
}
root->left =NULL;
root->right =NULL;
tmp = NULL;
}
return root;
}else if (root->value<value){
return deleteValue(root->right, root,value);
}else{
return deleteValue(root->left, root,value);
}
}
代码实现二:
/*
在root二叉搜索树中删除值为value的节点
1.叶子节点 直接删除
2.单儿子节点,直接将儿子放在父节点的下面
3.双儿子节点,直接找当前节点的直接后继
*/
struct Tnode* deleteValue2(struct Tnode** root,int value){
//没有找到需要删除的节点,直接返回NULL
if(root==NULL){
return NULL;
}
struct Tnode* deleteItem;
//如果root指向的节点,就是需要被删除的对象,则进行删除逻辑操作
if((*root)->value==value){
if((*root)->left==NULL && (*root)->right ==NULL){
deleteItem = *root;
*root = NULL;
}else if((*root)->left==NULL || (*root)->right ==NULL){
struct Tnode* child;
if((*root)->left == NULL){
child = (*root)->right;
(*root)->right = NULL;
}else{
child = (*root)->left;
(*root)->left = NULL;
}
deleteItem = *root;
(*root) = child;
}else{
//获取当前节点的直接后继
struct Tnode* tmp = (*root)->right;
struct Tnode* p = (*root);
while (tmp->left!=NULL) {
p = tmp;
tmp = tmp->left;
}
//如果直接后继,有右子树,则将右子树升级一下;没有,则将直接后继从树中脱离
if(tmp->right!=NULL){
if(p->left==tmp){
p->left = tmp->right;
}else{
p->right = tmp->right;
}
}else{
if(p->left==tmp){
p->left = NULL;
}else{
p->right = NULL;
}
}
tmp->left = NULL;
p = NULL;
//将tmp左右子树进行赋值
tmp->left = (*root)->left;
tmp->right = (*root)->right;
deleteItem = *root;
*root = tmp;
tmp = NULL;
}
return deleteItem;
}else if ((*root)->value<value){
return deleteValue2(&(*root)->right,value);
}else{
return deleteValue2(&(*root)->left,value);
}
}
二叉树的遍历
a. 前序遍历
b. 中序遍历
c. 后序遍历
前序遍历
/*
先序遍历
*/
void printPreTree(struct Tnode * root){
if(root==NULL){
return;
}
//打印当前节点的value
printf("%d ",root->value);
printPreTree(root->left);
printPreTree(root->right);
}
中序遍历
/*
中序遍历
*/
void printMidTree(struct Tnode* root){
if(root==NULL){
return;
}
//打印当前节点的value
printMidTree(root->left);
printf("%d ",root->value);
printMidTree(root->right);
}
后序遍历
/*
后序遍历
*/
void printPostTree(struct Tnode* root){
if(root==NULL){
return;
}
//打印当前节点的value
printPostTree(root->left);
printPostTree(root->right);
printf("%d ",root->value);
}