第4章第1节练习题11 查找最近公共祖先节点

问题描述

假设指针p和指针q分别指向二叉树中任意两个节点的指针,试编写算法找到p和q的最近公共祖先节点r

算法思想

因为计算的是公共祖先节点,因此可以考虑使用非递归后序遍历的思想。在非递归后序遍历的算法实现中,栈里面存放了即将入栈的元素的所有祖先节点。

为了方便表示说明,这里使用下图所描述的二叉树来说明。

假设指针p指向节点E,指针q指向节点G。

  • 按照正常的非递归后序遍历算法进行遍历,即借助栈S完成;
  • 当遍历到节点E时,将此时栈S中的元素复制到临时栈S1中。此时栈S1中的所有元素便为节点E的全部祖先节点;
  • 当编列到节点G时,将此时栈S中的元素复制到临时栈S2中。此时栈S2中的所有元素便为节点G的全部祖先节点;
  • 最后在分别按照从栈顶到栈底的顺序寻找栈S1和栈S2中的公共因子便可,第一个匹配到的便是节点E和节点G的最近公共祖先节点。

算法描述

void PostOrder(BiTNode* T)
{
    BiTNode *p=T;
    BiTNode *r=NULL;

    SqStack S;
    InitStack(&S);
    SqStack S1;
    InitStack(&S1);
    SqStack S2;
    InitStack(&S2);

    int flag=1;

    while(IsEmptyStack(&S)!=0||p!=NULL){
        if(p){
            Push(&S,p);
            p=p->lchild;
        }else{
            p=GetTop(&S);

            if(p->data==‘E‘){
                for(int i=0;i<=S.top;i++){
                    S1.data[i]=S.data[i];
                    S1.top=S.top;
                }
            }
            if(p->data==‘G‘){
                for(int i=0;i<=S.top;i++){
                    S2.data[i]=S.data[i];
                    S2.top=S.top;
                }
            }

            if(p->rchild!=NULL&&p->rchild!=r){
                p=p->rchild;
                Push(&S,p);
                p=p->lchild;
            }else{
                p=Pop(&S);

                if(IsEmptyStack(&S1)!=0&&IsEmptyStack(&S2)!=0){
                    for(int i=S1.top;i>-1&&flag;i--){
                        for(int j=S2.top;j>-1;j--){
                            if(S1.data[i]==S2.data[j]){
                                printf("%c",S1.data[i]->data);
                                flag=0;
                            }
                        }
                    }
                }

                r=p;
                p=NULL;
            }
        }
    }
}

具体代码见附件。


附件

//AB#DF##G##C#E##
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100

//---------------------------------------------------------------------

typedef char ElemType;
typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;

typedef struct{
    BiTNode* data[MaxSize];
    int top;
}SqStack;

void InitStack(SqStack*);
void Push(SqStack*,BiTNode*);
BiTNode* Pop(SqStack*);
BiTNode* GetTop(SqStack*);
int IsEmptyStack(SqStack*);

BiTree CreateBiTree(BiTNode*);
void PostOrder(BiTNode*);

//---------------------------------------------------------------------

int main(int argc,char* argv[])
{
    BiTNode *T;
    T=(BiTNode*)malloc(sizeof(BiTNode));
    T=CreateBiTree(T);
    PostOrder(T);
    printf("\n");
    return 0;
}

//---------------------------------------------------------------------

BiTree CreateBiTree(BiTNode* T)
{
    ElemType x;
    scanf("%c",&x);
    if(x==‘#‘){
        return T=NULL;
    }else{
        T=(BiTNode*)malloc(sizeof(BiTNode));
        T->data=x;
        T->lchild=CreateBiTree(T->lchild);
        T->rchild=CreateBiTree(T->rchild);
    }
    return T;
}

void PostOrder(BiTNode* T)
{
    BiTNode *p=T;
    BiTNode *r=NULL;

    SqStack S;
    InitStack(&S);
    SqStack S1;
    InitStack(&S1);
    SqStack S2;
    InitStack(&S2);

    int flag=1;

    while(IsEmptyStack(&S)!=0||p!=NULL){
        if(p){
            Push(&S,p);
            p=p->lchild;
        }else{
            p=GetTop(&S);

            if(p->data==‘E‘){
                for(int i=0;i<=S.top;i++){
                    S1.data[i]=S.data[i];
                    S1.top=S.top;
                }
            }
            if(p->data==‘G‘){
                for(int i=0;i<=S.top;i++){
                    S2.data[i]=S.data[i];
                    S2.top=S.top;
                }
            }

            if(p->rchild!=NULL&&p->rchild!=r){
                p=p->rchild;
                Push(&S,p);
                p=p->lchild;
            }else{
                p=Pop(&S);

                if(IsEmptyStack(&S1)!=0&&IsEmptyStack(&S2)!=0){
                    for(int i=S1.top;i>-1&&flag;i--){
                        for(int j=S2.top;j>-1;j--){
                            if(S1.data[i]==S2.data[j]){
                                printf("%c",S1.data[i]->data);
                                flag=0;
                            }
                        }
                    }
                }

                r=p;
                p=NULL;
            }
        }
    }
}

//---------------------------------------------------------------------

void InitStack(SqStack* S){
    S->top=-1;
}

void Push(SqStack* S,BiTNode* T){
    if(S->top==MaxSize-1){
        return;
    }
    S->data[++S->top]=T;
}

BiTNode* Pop(SqStack* S){
    if(S->top==-1){
        return NULL;
    }
    return S->data[S->top--];
}

BiTNode* GetTop(SqStack* S){
    if(S->top==-1){
        return NULL;
    }
    return S->data[S->top];
}

int IsEmptyStack(SqStack* S){
    if(S->top==-1){
        return 0;
    }else{
        return -1;
    }
}
时间: 2024-11-07 13:03:19

第4章第1节练习题11 查找最近公共祖先节点的相关文章

第1章第1节练习题10 查找中位数

问题描写叙述 一个长度为L(L ≥1) 的升序序列S.处在第 ? L/2 ? 个位置的数称为S的中位数.比如,若序列S1=(11,13,15,17,19).则S1的中位数是15. 两个序列的中位数是含它们全部元素所组成的升序序列的中位数. 比如,若S2=(2,4,6,8,20).则S1和S2的中位数是11. 如今有两个等长升序序列A和B,试设计一个在时间和空间都尽可能高效的算法.找出两个序列A和B的中位数. 算法思想 分别求两个升序序列A.B中位数,设为a和b 1). 若a=b,则a或b即为所求

第4章第1节练习题9 反向层次遍历算法

问题描述 试给出二叉树的自下而上,从右到左的层次遍历算法 算法思想 一般的二叉树层次遍历算法是自上向下,从左到右的遍历,这里的遍历顺序恰好相反,而运用栈先进后出的特点实现顺序的反转. 因此可以考虑在原来的层次遍历算法的基础上加上栈的基本操作.在出队的同时将各节点入栈,在所有的节点全部入栈后,依次出栈访问便可解决该问题. 算法描述 void InLevelOrder(BiTNode* T){ BiTNode *p=T; SqQueue Q; InitQueue(&Q); SqStack S; In

第4章第1节练习题6 二叉树叶子节点链接成单链表

问题描述 设计一个算法,将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head.链接时用叶子节点的右指针来存放单链表指针. 算法思想 题目要求将叶子节点按自左向右的次序连接成一个单链表,因此很容易考虑到的便是将整棵二叉树按照先序或中序或后序的方式遍历一次. 在遍历的过程中对叶子节点单独判断,如果是叶子节点,则将其做一个标识(比如用额外的指针指向该节点),接着遍历下一个叶子节点,遍历到另一个叶子节点后,然后让已被标识的叶子节点的右孩子指向该节点,依次类推便可以实现将叶子节点连接成单链

第2章第2节练习题3 使用队列模拟渡口管理

问题描写叙述 汽车轮渡口,过江渡船每次能载10辆车过江.过江车分为客车和货车类.上渡船有例如以下规定: 1).同类车先到先上船. 2).客车先于货车上渡船,其每上4辆客车,才同意放上一辆货车: 3).若等待客车不足4辆.则以货车取代: 4).若无货车等待,同意客车都上船. 试设计一个算法模拟渡口管理 算法思想 经过分析,发现此题实际上就是队列的基本操作,唯一的不同就是在入队的时候,对于顺序进行了限制. 使用队列Q表示每次载渡的车辆,队列Qp表示客车.Qt表示货车队列: 假设Qp中元素足够.则每从

第3章第1节练习题1 蛇形矩阵

问题描述 蛇形矩阵即使用二维数组完成来回曲折的赋值,举例说明如下所示的形式即为蛇形数组. 算法思想 观察该二维数组,只是可以"人为"的发现它就像一条蛇的形状来回爬行,然而并没有什么卵用,不能明确的站在计算机的角度上来实现这个数组.于是将所有的下标列出来便可以得到下述所述的曲线走势. 然后结合第一张图便可以发现 数字从2~3的过程中,下标行变化范围是0~1:下标列范围是1~0: 数字从4~6的过程中,下标行变化范围是2~0:下标列范围是0~2: 数字从7~10的过程中,下标行变化范围是0

第1章第2节练习题3 删除最小值结点

问题描写叙述 试编写在带头结点的单链表L中删除一个最小值结点的高效算法(如果最小值结点是唯一的) 算法思想 在链表中删除最小值的前提是必须找到最小值元素是哪个结点,因此设置指针p对全部结点进行遍历,使用指针min指向最小值结点.可是由于涉及到删除操作,明显在仅仅有指针min和指针p的条件下删除操作是极为不方便的. 若单纯的删除指针p指向的结点会造成断链.若採用2.5.2删除自身结点的方法,又会出现多次赋值操作. 因此直接引入两个分别指向其前驱结点的指针pre和premin,如此.删除操作过程会更

第1章第2节练习题4 删除指定区间结点

问题描述 设一个带表头结点的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有其值在给定值s与t之间(包含s和t,要求s<t)的所有结点 算法思想 因为链表逻辑上无序,删除指定区间结点的前提是找到这些指定区间结点.因此从头节点开始对整个链表进行一次遍历,若找到满足题意的结点,删除即可. 算法描述 void Delts(LNode* head, ElemType t, ElemType s) { LNode *pre=head; LNode *p=head->next; while(

第4章第1节练习题10 判断某二叉树是否为完全二叉树

问题描述 试写一算法,完成判定某二叉树是否为完全二叉树的功能 算法思想 根据完全二叉树的定义,具有n个节点的完全二叉树与满二叉树中的编号从1~n的节点一一对应,可以考虑使用层次遍历的思想来实现. 将所有节点入队(包括空节点).当遇到空节点时,查看其后是否还有不为空的节点:如果没有,则为完全二叉树:如果有,则不是完全二叉树: 算法描述 int IsComplete(BiTNode* T){ SqQueue Q; InitQueue(&Q); BiTNode *p=T; EnQueue(&Q,

第1章第2节练习题2 非递归删除指定结点

问题描写叙述 在带头结点的单链表L中.删除全部值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法实现以上的操作 算法思想 使用指针p指向数据域为x的结点.使用指针pre指向指针p所指结点的前驱结点,从前向后进行遍历.假设指针p指向的结点的数据域为x,则删除.假设指针p指向的结点的数据域不为x,继续向后遍历就可以. 算法描写叙述 void DelNodeX(LNode *head, ElemType x) { LNode *pre=head; LNode *p=head->next;