最近共同祖先

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/richrdbird/article/details/52778128


#include <iostream>
#include <vector>
using namespace std;

// 参考 http://blog.csdn.net/cxllyg/article/details/7635992
// 参考 《剑指offer》P256

struct node{
  int data;
  node *left;
  node *right;

  node(const int &x, node *l = NULL, node *r = NULL){
    data = x;
    left = l;
    right = r;
  }
  ~node(){}
};

bool node_path(node *p, node *root, vector<node *> &path){
  if(root == NULL)
    return false;

  if(p == root){
    path.push_back(root);
    return true;
  }

  // 倒序保存
  //if(node_path(p, root->left, path)){
  //  path.push_back(root);
  //  return true;
  //}
  //else if(node_path(p, root->right, path)){
  //  path.push_back(root);
  //  return true;
  //}
  //else {
  //  return false;
  //}

  // 顺序保存
  path.push_back(root);
  bool found = false;
  if(node_path(p, root->left, path)){
    found = true;
  }
  else if(node_path(p, root->right, path)){
    found = true;
  }
  else {
    found = false;
  }
  if(!found){
    path.pop_back();
  }
  return found;
}

node *find_lowest_common_ancestor(node *p1, node *p2, node *root){
  vector<node *> path1, path2;
  bool find1 = node_path(p1, root, path1);
  bool find2 = node_path(p2, root, path2);
  if(!(find1 && find2))
    return NULL;
  node *ancestor = root;
  // 倒序取最近共同祖先
  //int max_common_len = path1.size() < path2.size() ? path1.size() : path2.size();
  //for(int i = 0; i < max_common_len; ++i){
  //  if(path1[path1.size() - 1 - i] != path2[path2.size() - 1 - i])
  //    break;
  //  ancestor = path1[path1.size() - 1 - i];
  //}
  // 顺序取最近共同祖先
  int max_common_len = path1.size() < path2.size() ? path1.size() : path2.size();
  for(int i = 0; i < max_common_len; ++i){
    if(path1[i] != path2[i])
      break;
    ancestor = path1[i];
  }
  return ancestor;
}

int main(){
  node *tmp;
  node *p1;
  node *p2;

  node *root = new node(1);
  tmp = new node(2);
  root->left = tmp;
  tmp = new node(3);
  root->right = tmp;
  tmp = new node(4);
  root->left->left = tmp;
  tmp =  new node(5);
  root->left->right = tmp;
  tmp = new node(6);
  p1 = tmp;
  root->left->left->left = tmp;
  tmp = new node(7);
  root->left->left->right = tmp;
  tmp = new node(8);
  p2 = tmp;
  root->left->right->left = tmp;
  tmp = new node(9);
  root->left->right->right = tmp;

  node *ancestor = find_lowest_common_ancestor(p1, p2, root);
  cout << "ancestor: " <<ancestor->data << endl;

  int ttt = 0;
  return 0;
}



展开阅读全文

求二叉树重量节点最近共同祖先

12-30

要求:假设二叉树采用二叉链表的结构存储,P和q为二叉树中的连个节点,编写程序计算他们最近的共同祖先并输出。rn 1,拟定合适的二叉树的输入形势和构造算法rn 2,能够以直观的形式观观察所建立的二叉树的结构rn 3,独立完成系统的设计,编码和调试rn 4,系统利用C语言实现rn rnrnrn这是我写的程序,没有错误,但运行不了啊,能不能请高手指点一下啊!若果觉得这个程序不好,也恳请用更好的方法写一下,麻烦大家了rnrnrnrnrn#include rn#include rn#include rn#define ERROR 0rn#define OK 1rn#define STACK_INIT_SIZE 100 //栈的存储空间初始分配量rn#define STACKINCREMENT 10 //栈的存储空间初始分配增量rn rntypedef int Status;rntypedef int TElemType;rntypedef struct BiTNodernrn TElemType data;rn struct BiTNode *lchild,*rchild;rnBiTNode,*BiTree;//二叉树的二叉链表储存结构rn rntypedef structrnrn TElemType data;//保存当前输入的结点的数据域rn char child;//child='D' 表示该结点有左右孩子;child='L' 表示该结点仅有左孩子rn //child='R' 表示该结点仅有右孩子;child='O' 表示该结点无左右孩子rnNodeStatus;rn rntypedef BiTNode **QElemType;rntypedef struct QNodernrn QElemType data;rn struct QNode *next;rnQNode,*QueuePtr;rn//队列的结点结构rntypedef structrnrn QueuePtr front;//队头指针,这里指向队列的头结点(是带头结点的队列)rn QueuePtr rear;//队尾指针,指向队尾元素rnLinkQueue;rn//单链队列,队列的链式储存结构rn rn rn rnStatus InitQueue(LinkQueue *LQ)rn//构造一个空队列,只有头结点rn if(!(LQ->front=(QueuePtr)malloc(sizeof(QNode)))) return ERROR;//生成头结点rn LQ->front->next=NULL;rn LQ->rear=LQ->front;rn return OK;rn//InitQueuern rnStatus EnQueue(LinkQueue *LQ,QElemType e)rn//插入元素e为队列*LQr队尾元素rn QNode *p;rn if(!(p=(QNode*)malloc(sizeof(QNode)))) return ERROR;rn p->data=e;rn p->next=NULL;rn LQ->rear->next=p;rn LQ->rear=p;rn return OK;rn//EnQueuern rnStatus DeQueue(LinkQueue *LQ,QElemType *e)rn//若队列不空,则删除队头元素(即首元结点),并用*e返回结果;否则函数返回ERRORrn if(LQ->front==LQ->rear) return ERROR;rn *e=LQ->front->next->data;rn LQ->front->next=LQ->front->next->next;//队头元素出队列rn if(LQ->front->next==NULL) //哦,原来这里出错了××××××rn LQ->rear=LQ->front;//若队列变为空,则修改队尾指针rn return OK;rn//DeQueuern rnStatus DestroyQueue(LinkQueue *LQ)rn//销毁队列rn QNode *p;rn while(LQ->front!=LQ->rear)rn rn p=LQ->front->next;rn LQ->front->next=LQ->front->next->next;rn if(LQ->front->next==NULL)rn LQ->rear=LQ->front;//若队列变为空,则修改队尾指针rn free(p);rn //whilern free(LQ->front);//释放队头结点rn return OK;rn//DestroyQueuern rn rn rn rn rnrnStatus CreateBiTree(BiTree *T,char *s)rn//按层次顺序(从上自下,同一层次从左至右)输入二叉树中结点的值以及该结点拥有的孩子的情况rn //构造二叉链表表示的二叉树T;若s="NULL",表示构造一棵空二叉树,若s="NOTNULL" 表示二叉树非空rn if(T==NULL ||(strcmp(s,"NULL") && strcmp(s,"NOTNULL"))) return ERROR;//参数非法,入口断言rn rn if(!strcmp(s,"NULL")) rn //构造空树rn *T=NULL;rn printf("构造了一个空二叉树!/n");rn return OK;rn //ifrn rn //若能来到这里,表明构造一个非空二叉树rn printf("构造一个非空二叉树!/n");rn rn NodeStatus NS;//保存当前输入的结点的值以及该结点拥有的孩子的情况rn LinkQueue LQ;//定义一个辅助队列rn InitQueue(&LQ);//构造一个只有头结点的空队列rn EnQueue(&LQ,T);//初始化队列元素rn QElemType p;//用p返回队头元素中的数据域rn char c=' ';//输助变量,用以确定输入的二叉树的结点是否结束;循环初始化字符crn rn while(c!='/n')rn rn scanf("%d %c",&(NS.data),&(NS.child));rn //printf("NS.data=%d NS.child=%c/n",NS.data,NS.child );rn rn DeQueue(&LQ,&p);//取队头元素的数据域,并使队头元素出队列rn if(!((*p)=(BiTNode*)malloc(sizeof(BiTNode)))) return ERROR;rn //生成一个结点rn (*p)->data=NS.data;//二叉树中该结点的值rn //printf("(*p)->data=%d/n",(*p)->data);rn rn (*p)->lchild=NULL;//这里不能漏的吧rn (*p)->rchild=NULL;//这里不能漏的吧rn rn if(NS.child=='D')rn //该结点有左右孩子rn EnQueue(&LQ,&((*p)->lchild));rn EnQueue(&LQ,&((*p)->rchild));rn //if NS.child=='D'rn else if(NS.child=='L')rn //该结点仅有左孩子rn EnQueue(&LQ,&((*p)->lchild));rn // else if NS.child=='L'rn else if(NS.child=='R')rn //该结点仅有右孩子rn EnQueue(&LQ,&((*p)->rchild));rn //else if NS.child=='R'rn rn c=getchar();rn rn //whilern rn DestroyQueue(&LQ);rn rn return OK;rn//CreateBiTreern rnStatus VisitNode(BiTNode *p)rn//访问二叉树中结点的数据域rn if(p==NULL) return ERROR;rn printf("%d ",p->data);rn return OK;rn//VisitNodern rnStatus PreOrderTraverse(BiTree T,Status (*V)(BiTNode *))rn//先序遍历二叉树rn if(T==NULL) return OK;rn if((*V)(T))rn if(PreOrderTraverse(T->lchild,V))rn if(PreOrderTraverse(T->rchild,V))rn return OK;rn return ERROR;rn//PreOrderTraversern rnStatus PreOrderTraverse_2(BiTree T,TElemType e,BiTNode **p)rn//先序遍历二叉树,若找到一个结点的值与e 相等,则用*p指针返回这个结点的地址;否则函数返回ERRORrn if(T==NULL) return ERROR;rn if(T->data ==e)rn rn *p=T;rn //ifrn else rn rn if(!(PreOrderTraverse_2(T->lchild,e,p)))rn if(!(PreOrderTraverse_2(T->rchild,e,p)))rn return ERROR;rn //elsern return OK;rn//PreOrderTraversern rnrntypedef structrnrn BiTNode *data;rn int tag;rnSElemType;//栈元素结点结构rn rntypedef structrnrn SElemType *base; //栈底指针,在栈构造之前和销毁之后,base的值为 NULLrn SElemType *top; //栈顶指针,指向栈项元素的下一位rn int stacksize; //当前已分配的存储空间,以元素SElemType为单位rnSqStack; //栈的顺序存储表示rn rnStatus InitStack(SqStack *S)rn//构造一个空栈rn if(S==NULL) return ERROR;//参数非法rn if(!(S->base=(SElemType*)malloc(sizeof(SElemType)*STACK_INIT_SIZE))) return ERROR;rn //分栈的初始空间rn S->top=S->base;//初始化栈为空栈rn S->stacksize=STACK_INIT_SIZE;rn return OK;rn//InitStackrn rnrnStatus PushStack(SqStack *S,BiTNode *data,int tag)rn//插入一个栈顶元素,并以data和tag为新的栈顶元素的数据域rn if(S->top-S->base==S->stacksize)rn //栈满rn if(!(S->base=(SElemType*)realloc(S->base,sizeof(SElemType)*(S->stacksize+STACKINCREMENT))))rn return ERROR;rn S->stacksize+=STACKINCREMENT;rn return OK;rn //ifrn rn S->top->data=data;rn S->top->tag=tag;rn S->top++;rn return OK;rn//PushStackrn rnStatus PopStack(SqStack *S,BiTNode **p)rn//若栈不空,则删除栈顶元素,并用*p返回栈顶元素中的data域的值rn if(S->base==S->top || p==NULL) return ERROR;rn *p=(S->top-1)->data;rn S->top--;rn return OK;rn//PopStackrn rnStatus DestroyStack(SqStack *S)rn//销毁栈rn free(S->base);rn S->base=S->top=NULL;rn S->stacksize=0;rn return OK;rn//DestroyStackrn rnStatus FiClosForfather(BiTree T,BiTNode *p,BiTNode *q,BiTNode **Forf)rn//找二叉树T中的两结点*p和*q的最近共同祖先,并用*Forf返回这个最近共同祖先rn if(T==NULL || p==NULL || q==NULL || Forf==NULL ) return ERROR;//参数非法,入口断言rn rn int m=0;//每次拭到结点*p和*q中的一个时,m++rn int n=0;//当m=0时,表示当前栈顶元素的指针域data所指向的二叉树中的结点的祖先的个数rn //当m!=0时,表示首次找到结点*p和*q中一个时,这个结点的祖先的个数;在这之后,rn //如果这些祖先出栈,则n自减1rn rn SqStack S;rn InitStack(&S);rn PushStack(&S,T,0);rn while(m!=2 && S.base!=S.top)rn rn if((S.top-1)->tag==0)rn //在这之前未曾到过这个结点,现在是第1次来到这个结点rn (S.top-1)->tag=1;rn if((S.top-1)->data==p || (S.top-1)->data==q)rn //找到结点*p和*q中的一个rn m++;rn if(p==q)rn m++;rn //ifrn rn if((S.top-1)->data->lchild!=NULL)rn rn PushStack(&S,(S.top-1)->data->lchild,0);//左孩子进栈rn if(m==0)rn n++;rn //if rn //if (S.top-1)->tag==0rn else if((S.top-1)->tag==1)rn //在这之前已经有1次来到这个结点,现在是第2次rn (S.top-1)->tag=2;rn if((S.top-1)->data->rchild!=NULL)rn rn PushStack(&S,(S.top-1)->data->rchild,0);//右孩子进栈rn if(m==0)rn n++;rn //ifrn //else if (S.top-1)->tag==1rn elsern //即 (S.top-1)->tag==2 表明在这之前已有2次到过这个结点,现在是第3次,要出栈了,即“回退”rn if(m==1 && (S.top-S.base)==n)rn n--;rn //已经找到两结点*p和*q中的一个了!rn if(m==0)rn n--;rn //还未找到两结点*p和*q中的任一个!rn S.top--;//栈顶元素出栈rn //else rn //whilern rn if(m==2)rn //在二叉树T中同时找到结点*p和*q,那么当然可以找到这两个结点的最近共同祖先rn *Forf=NULL;//初始化;必须,如果结点*p和*q中有一个与结点*T相同,那么,因为*T树根无双亲,rn //那此时结点*p和*q的最近共同祖先不存在rn SElemType *temp;rn temp=S.base;rn for(int i=1;i<=n;i++)rn rn *Forf=temp->data;rn temp++;rn //forrn DestroyStack(&S);rn return OK;//找到结点*p和*q的最近共同祖先rn //ifrn DestroyStack(&S);rn return ERROR;//因为结点*p和*q不全在二叉树T中,导致找不到这两个结点的最近共同祖先rn//FiClosForfatherrn rnrnvoid main()rnrn Status (*V)(BiTNode*);rn V=VisitNode;rn BiTree T;rn CreateBiTree(&T,"NOTNULL");rn printf("先序遍历二叉树:/n");rn PreOrderTraverse(T,V);rn printf("/n");rn rn BiTNode *root,*p,*q;rn PreOrderTraverse_2(T,1,&root);//结点的值为 1 的结点rn PreOrderTraverse_2(T,11,&p);//结点的值为 12 的结点rn PreOrderTraverse_2(T,7,&q);//结点的值为 7 的结点rn //从二叉树中找任意的3个结点,分别用指针root p q 返回这3个结点(约定都能)rn printf("root->data=%d/np->data=%d/nq->data=%d/n",root->data,p->data,q->data);rn rn BiTNode *Forf;rn int result=FiClosForfather(root,p,q,&Forf);rn rn if(result==1)rn rn if(Forf!=NULL)rn printf("结点*p和*q的最近共同祖先是:%d/n",Forf->data);rn elsern printf("结点*p和*q的最近共同祖先是:0/n");rn //ifrn elsern printf("找不到结点*p和*q的最近共同祖先!/n");rn rnrn//mainrnrnrnrn 论坛

没有更多推荐了,返回首页