二叉树后继

本文介绍如何在二叉树中寻找指定节点的后继节点。提供了两种情况下的解决方案:一种是有指向父节点的情况,另一种是没有指向父节点的情况。对于后者,分别使用栈和递归实现了中序遍历。

二叉树后继

如果有指向父亲的结点,则:

1.如果当前结点有右儿子,或者当前结点是根结点,则后继结点为右子树的最左叶节点;
2.否则,如果当前结点是父结点的左儿子,则后继结点就是父结点;(其实是第三种情况的一个特例,即自己是第0代祖先,返回第一代祖先)
3.否则,向上遍历,直到n-1代祖先是n代祖先的左儿子,则后继结点为n代祖先;或者遍历到根节点后未找到符合的n代结点,则该结点为中序遍历的最后结点,没有后继。

时间复杂度为树的高度O(lgN)。

    struct TreeNode  
    {  
        char key;  
        TreeNode *left;  
        TreeNode *right;  
        TreeNode *parent;  
    };  

    TreeNode *FindSuccessor(TreeNode *x)  
    {  
        if(x->right!=NULL)  
        {  
            TreeNode *q=x->right;  
            while(q->left)  
                q=q->left;  
            return q;  
        }  
        TreeNode *p=x->parent;  
        while(p&&x==p->right)  
        {  
            x=p;  
            p=p->parent;  
        }  
        return p;  
    }  

如果没有父指针,则通过栈来实现中序遍历:

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};

class Successor {
public:
    int findSucc(TreeNode *root,int p){
        stack<TreeNode *> st;
        bool isFound=false;
        TreeNode *cur=root;
        while(cur||!st.empty()){
            if(cur!=NULL){
                st.push(cur);
                cur=cur->left;
            } else {
                cur=st.top();st.pop();
                if(isFound==true)return cur->val;
                if(cur->val==p)isFound=true;
                cur=cur->right;
            }
        }
        return -1;
    }
};

也可以通过递归实现:

class Successor {
public:
    int findSucc(TreeNode* root, int p) {
        // write code here
        bool sign=0;
        return findSucc1(root,p,sign);
    }
    int findSucc1(TreeNode* root,int p,bool &sign)
    {
        if(root==NULL)
            return -1;
        int left=findSucc1(root->left,p,sign);
        if(left!=-1)
            return left;
        if(sign==true)
            return root->val;
        if(root->val==p)
            sign=true;
        return findSucc1(root->right,p,sign);
    }
};
### 线索二叉树中的前驱和后继节点概念 线索二叉树是一种通过增加额外标记位来优化二叉树遍历效率的数据结构。它通过对每个节点的左右指针进行扩展,引入 `ltag` 和 `rtag` 字段,分别指示该节点的左孩子或右孩子的指向是否为实际子节点还是线索[^1]。 #### 前驱节点定义 在一个中序遍历序列中,某节点的前驱是指在其之前被访问到的第一个节点。如果当前节点存在左子树,则其前驱是左子树中最右侧的叶子节点;如果没有左子树,则可以通过 `ltag` 判断是否存在直接前驱线索[^4]。 #### 后继节点定义 同样,在中序遍历序列中,某节点的后继是在其之后立即被访问的一个节点。如果当前节点有右子树,则它的后继就是右子树中最左侧的叶子节点;否则可以利用 `rtag` 来判断是否有直接后继线索[^3]。 --- ### 实现算法分析 以下是基于 C/C++ 的具体实现方式: #### 查找前驱节点 ```c ThreadedNode* preSuccessor(ThreadedNode* p) { if (p->ltag == 0) { // 左子节点不为空的情况 ThreadedNode* q = p->left; while (q->rtag == 0 && q->right != NULL) { // 找到最右边的节点 q = q->right; } return q; } else { // 存在前驱线索 return p->left; } } ``` 此函数用于获取给定节点 `p` 的前驱节点。当 `ltag=0` 表明左指针指向的是真实子节点而非线索时,需沿左子树一路向右寻找直至尽头得到最终结果;反之则直接返回存储于 `left` 中的目标地址作为前驱位置[^1]。 #### 查找后继节点 ```c ThreadedNode* postSuccessor(ThreadedNode* p) { if (p->rtag == 0) { // 右子节点不为空的情况下 return p->right; // 返回右子节点本身即可 } else { // 需要从右子树内部继续探索 ThreadedNode* q = p->right; while (q->ltag == 0 && q->left != NULL) { // 寻找最左边的节点 q = q->left; } return q; } } ``` 这段代码实现了如何定位任意指定节点 `p` 的后续接替者逻辑。若发现 `rtag=0` ,意味着可以直接跳转至关联目标处完成操作;然而一旦遇到标志设置成线索单元形式(`rtag=1`),就需要深入挖掘对应分支路径上的首个可用选项[^3]。 需要注意的是,在特殊情况下比如处理 **后序线索化** 结构时,并不存在简单有效的手段去单独确定某个定点后的下一个顺序成员关系,此时可能不得不借助全局扫描机制或者其他辅助工具来进行补充计算[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值