情况1:
树为二叉排序树。
思路:从根结点开始和输入的两个结点进行比较,如果当前结点的值比两个结点的值都大,那么最低的祖先肯定在左子树中,于是下一步遍历当前结点的左子结点。如果当前结点的值比两个结点的值都小,那么最低的祖先肯定在右子树种,于是下一步遍历当前结点的右子结点。如果当前结点正好是输入的两个结点之一,说明这两个结点有一个是另一个的祖先,这时输出当前结点的父节点即可。
/* 二叉树的公共祖先系列 1.二叉树为二叉排序树 by Rowandjj 2014/8/20 */ #include<iostream> using namespace std; typedef struct _NODE_ { int data; struct _NODE_ *left; struct _NODE_ *right; }BNode,*pBNode,*pTree; //先序方式构造二叉树 void create(pTree *pT) { int data; cin>>data; if(data == -1) { return; } *pT = (pBNode)malloc(sizeof(BNode)); if(!pT) { exit(-1); } (*pT)->data = data; (*pT)->left = NULL; (*pT)->right = NULL; create(&(*pT)->left); create(&(*pT)->right); } pBNode findAncestor(pTree pT,pBNode pNode1,pBNode pNode2) { if(pT == NULL || pNode1 == NULL || pNode2 == NULL) { return NULL; } if(pT == pNode1 || pT == pNode2)//输入的结点中至少有一个是根,这种情况下无祖先 { return NULL; } pBNode pParent = NULL; int pData1 = pNode1->data; int pData2 = pNode2->data; if(pData1 > pData2) { int temp = pData1; pData1 = pData2; pData2 = temp; } while(pT != NULL) { if(pT->data < pData1)//当前结点比输入的两个结点都小 {//说明在右子树中 pParent = pT; pT = pT->right; }else if(pT->data > pData2)//当前结点比输入的两个结点都大 {//说明在左子树中 pParent = pT; pT = pT->left; }else if(pT == pNode1 || pT == pNode2)//当前结点正好是输入的结点之一,说明输入的两个结点一个是另一个的祖先 { return pParent; }else//当前结点值在输入的两个结点之间 { return pT; } } return NULL; } void display(pTree pT) { if(pT == NULL) { return; } if(pT->left) { display(pT->left); } cout<<pT->data<<" "; if(pT->right) { display(pT->right); } } int main() { pTree pT = NULL; create(&pT); display(pT); cout<<"\n"; pBNode n = (pBNode)malloc(sizeof(BNode)); if(!n) { exit(-1); } n->data = 111; pBNode p = findAncestor(pT,n,n); if(p != NULL) { cout<<p->data<<endl; } else { cout<<"Not Found\n"; } return 0; }
情况2:
二叉树是普通二叉树,但是含有指向父节点的指针.
思路:
既然含有指向父节点的指针,那么我们从输入的两个结点分别出发,得到两条到根结点的路径,然后问题转化为求两个单链表的第一个公共结点问题.
代码:
/* 二叉树公共祖先系列 2.二叉树含有指向父节点的指针 */ #include<iostream> using namespace std; typedef struct _NODE_ { int data; struct _NODE_ *left; struct _NODE_ *right; struct _NODE_ *parent; }Node,*pNode,*pTree; /*寻找最低公共祖先*/ pNode findAncestor(pTree pT,pNode pNode1,pNode pNode2) { if(pT == NULL || pNode2 == NULL || pNode1 == NULL) { return NULL; } if(pT==pNode1 || pT==pNode2) { return NULL; } /* 1.计算这两个结点到根结点的路径长度 */ int len1 = 0,len2 = 0; pNode pTemp = pNode1; while(pTemp != NULL) { pTemp = pTemp->parent; len1++; } pTemp = pNode2; while(pTemp != NULL) { pTemp = pTemp->parent; len2++; } /* 2.接下来相当于求两个单链表的公共结点 */ int dif = len1-len2; pNode pLong = pNode1; pNode pShort = pNode2; if(dif<0) { pLong = pNode2; pShort = pNode1; dif = len2-len1; } while(dif > 0)//快指针先走dif步 { pLong = pLong->parent; dif--; } //两个指针同时走,第一次相遇即为最低公共祖先 while(pLong != NULL && pShort != NULL && pLong != pShort) { pLong = pLong->parent; pShort = pShort->parent; } return pLong; } /*先序遍历*/ void display(pTree pT) { if(pT == NULL) { return; } cout<<pT->data<<" "; if(pT->left) { display(pT->left); } if(pT->right) { display(pT->right); } } /*构建二叉树*/ void create(pTree *pT,pNode pParent) { int data; cin>>data; if(data == -1) { return; } *pT = (pNode)malloc(sizeof(Node)); if(*pT == NULL) { exit(-1); } (*pT)->data = data; (*pT)->left = NULL; (*pT)->right = NULL; (*pT)->parent = pParent; create(&(*pT)->left,*pT); create(&(*pT)->right,*pT); } int main() { pTree pT = NULL; create(&pT,NULL); pNode p = findAncestor(pT,pT->right,pT->left->right->left->right); if(p != NULL) { cout<<p->data<<endl; }else { cout<<"Not Found..."<<endl; } display(pT); return 0; }
情况3:
树为普通二叉树,没有指向父节点的指针
思路:
首先第一步仍然需要求到输入的两个结点到根结点的一条路径,然后有了路径就好办了。
我们可以使用一个数组存放路径,然后按照先序遍历的方式得到路径,具体见代码。
代码:
/* 树中两个结点的公共祖先 3.树为普通二叉树,没有指向父节点的指针 */ #include<stdio.h> #include<stdlib.h> typedef struct _NODE_ { int data; struct _NODE_ *left; struct _NODE_ *right; }Node,*pNode,*pTree; /* 在二叉树pT中寻找从根到val的一条路径,path保存路径数组,index为当前数组下标,len为数组长度 */ bool GetNodePath(pTree pT,int val,int *path,int index,int *len) { if(pT == NULL) { *len = 0; return false; } path[index] = pT->data; if(pT->data == val) { *len = index+1;//index从0开始 return true; }else { bool can; can = GetNodePath(pT->left,val,path,index+1,len); if(!can) { can = GetNodePath(pT->right,val,path,index+1,len); } return can; } } /* 寻找最低公共祖先 根据两条路径 */ int findAncestor(int *path1,int len1,int *path2,int len2) { if(path1 == NULL || path2 == NULL || len1 <= 0 || len2 <= 0) { return 0; } int minLen = (len1<len2)?len1:len2; int i; for(i = 0; i < minLen; i++) { if(path1[i] != path2[i])//第一个不相同的结点的上一个结点即为最低公共祖先 { break; } } return path1[i-1]; } /*二叉树先序创建*/ void create(pTree *pT) { int data; scanf("%d",&data); if(data == 0) { return; } *pT = (pNode)malloc(sizeof(Node)); if(*pT == NULL) { exit(-1); } (*pT)->data = data; (*pT)->left = NULL; (*pT)->right = NULL; create(&(*pT)->left); create(&(*pT)->right); } /*先序遍历*/ void display(pTree pT) { if(pT == NULL) { return; } printf("%d ",pT->data); if(pT->left) { display(pT->left); } if(pT->right) { display(pT->right); } } /*销毁二叉树*/ void destroy(pTree pT) { if(pT == NULL) { return; } if(pT->left) { destroy(pT->left); } if(pT->right) { destroy(pT->right); } free(pT); pT = NULL; } int main() { int t; while(scanf("%d",&t) != EOF) { int i; int m,n; int len1,len2; for(i = 0; i < t; i++) { pTree pT = NULL; create(&pT); scanf("%d %d",&m,&n); int path1[10000]; int path2[10000]; GetNodePath(pT,m,path1,0,&len1); GetNodePath(pT,n,path2,0,&len2); int result = findAncestor(path1,len1,path2,len2); if(result != 0) { printf("%d\n",result); }else { printf("My God\n"); } destroy(pT); } } return 0; }
树中两个结点的最低公共祖先
时间: 2024-10-03 22:05:16