2024王道408数据结构 P144 T13

2024王道408数据结构 P144 T13

思考过程

  1. 题目言简意赅就是让我们找p和q的最近公共祖先结点,这题其实跟上一题差不多,都是用后序遍历+非递归+辅助栈来完成。
  2. 首先我们需要两个辅助栈,因为有一个指针p一个指针q,我们尽可能一次遍历就实现题目的算法。其次我们和上一题一样**需要一个tag值来判断该结点的左右子树是否遍历过,当tag=0时说明该结点的左子树我们已经遍历过,当tag=1时说明该结点的右子树我们也遍历过了。**我们找到元素先往s1栈里面放,当找到结点p时,把此时所有在栈1中的元素复制到栈2中,再用栈1去找q结点。
  3. 最后当我们找到q结点时,开始对比栈1和栈2之间到元素,当我们找到相同元素的时候就说明那个元素就是我们要找的公共祖先结点。

举个例子

  1. 请出我们的老演员二叉树,假设二叉树长这个样子,旁边是两个辅助栈s1和s2,假设p指针的结点为E,q指针的结点为E。请添加图片描述2. 清楚了我们上面所说的思路后我们先后序遍历该二叉树。我们需要一个指针l来帮我们遍历,struct TreeNode *l = t;首先第一步把头结点A入栈s1,把A的tag值赋为0,然后一路向左遍历二叉树B和D,把B和D的tag值都赋为0,说明此时已经遍历完他们的左子树了。然后遍历D都坐左子树发现D没有左子树,再去遍历D的右子树发现D也没有右子树,此时D的tag值为1,说明D的左右子树我们都遍历过了。请添加图片描述所有操作都在s1中完成。
  2. 当我们把A的所有左子树都遍历完后我们发现还是没找到p指针,那我们把D给出栈,因为D的tag值已经为1。出栈后栈顶指针top1指向B,再去遍历B的右子树E,把E入栈,发现此时的栈顶元素E就是我们要找的p。所以我们s1中的元素全部复制到s2中,顺便移动top指针top2=top1;请添加图片描述接下来再去找A到右子树C,把C结点入栈到s1。
  3. 循环往复一直当我们找到结点F,此时s1中的元素为ACF。请添加图片描述然后我们就开始匹配s1和s2中的元素,这里用for循环就能很方便的遍历栈中元素,当我们找到两个栈中有相同的元素A时s1[i]==s2[j];**就说明这就是我们要找的公共祖先结点。**这题到这里就做完了。

完整代码

//
// Created by 黎圣  on 2023/8/20.
//
/*
 * 13. 设一棵二叉树的结点结构为 (IIINK,INFO, RLINK),ROOT 为指向该二叉树根结点的指针,
 * p和g分别为指向该二叉树中任意两个结点的指针,试编写算法ANCESTOR (ROOT,p,q,r),找到
 * p和q的最近公共祖先结点r。
 */
#include "iostream"
using namespace std;
typedef struct TreeNode
{
    char data;
    struct TreeNode *lchild, *rchild;
}*tree, treenode;
struct Stack
{
    struct TreeNode *t;
    int tag;
};
void CreateTree(tree &t)
{
    char ch = getchar();
    if (ch == '#')
        t = NULL;
    else
    {
        t = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        t->data = ch;
        t->lchild = NULL;
        t->rchild = NULL;
        CreateTree(t->lchild);
        CreateTree(t->rchild);
    }
}
struct TreeNode *Ancestor(tree t,struct TreeNode *p, struct TreeNode *q)
{
    //两个辅助栈
    Stack s1[10], s2[10];
    //栈顶指针初始化
    int top1 = 0, top2;
    //遍历二叉树的指针
    struct TreeNode *l = t;
    while (l != NULL || top1 > 0)
    {
        //像左延伸入栈
        while (l != NULL)
        {
            s1[++top1].t = l;
            s1[top1].tag = 0;
            l = l->lchild;
        }
        //判断是否结点是否为p
        //栈1不为空切栈顶元素tag值为1
        while (top1 != 0 && s1[top1].tag == 1)
        {
            //如果栈顶元素就是p我们就把栈1中的元素复制到栈2中
            if (s1[top1].t == p)
            {
                for (int i = 1; i <= top1; i++)
                {
                    s2[i] = s1[i];
                }
                top2 = top1;
            }
            //如果栈顶元素就是q,我们就开始和栈2中的元素开始匹配
            if (s1[top1].t == q)
            {
                for (int i = top1; i > 0; i--)
                    for (int j = top2; j > 0; j--)
                        if (s2[j].t == s1[i].t)
                            return s1[i].t;
            }
            //两个情况都不满足的同时tag=1就出栈
            top1--;
        }
        //右子树入栈
        if (top1 != 0)
        {
            s1[top1].tag = 1;
            l = s1[top1].t->rchild;
        }
    }
    return NULL;
}
int main()
{
    tree t;
    CreateTree(t);
    struct TreeNode *p = t->lchild->rchild;
    struct TreeNode *q = t->rchild->lchild;

    //ABD##E##CF##G##
    printf("%c", Ancestor(t, p, q)->data);
    return 0;
}

累的不行,一开始在main函数里先赋值了p和q再建树t,发现怎么运行都不对,找错找了半小时…我纯🤡,最后感谢b站up主@吸血小金鱼

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值