算法之树-二叉搜索树(C语言)

二叉查找树(二叉搜索树)

定义:

1. 左子树的节点均小于根节点
2. 右子树的节点均不小于根节点
3. 左右子树也满足上面的两个条件

如下图所示:

lBenqP.png

二叉查找树的查找
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);
}
发布了98 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/dirksmaller/article/details/103841200