求二叉树中两个节点的最近公共祖先节点

二叉搜索树:

如果给定了一个二叉搜索树任意的两个节点的值,要求找到这两个结点的最近的公共结点:


输入12和8

输出 10

它们有共同的祖先10和25,选择最近的祖先10;

算法:

给定两个节点node1和node2,如果node1<node2,所以最近的公共祖先节点的值应该在node1和node2之间。

所以我们可以前序遍历这个二叉搜索树

若遍历到一个节点大于node2,所要求的结点就在此结点左侧,如遍历到15,那就在15左边

否则在此结点的右边


二叉树:

方法一:

找到从根到n1的路径,并存储在一个vector中。
找到从根到n2的路径,并存储在一个vector中。
 遍历这两条路径,直到遇到一个不同的节点,则它前面的那个为最低公共祖先.

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


struct Node
{
int key;
struct Node *left;
struct Node *right;
};
Node * newNode(int k)
{
Node *temp = new Node;
temp->key = k;
temp->left = NULL; 
temp->right = NULL;
return temp;
}
bool findpath(Node * root, vector<int> &path, int key)
{
if (root == NULL)
return false;
path.push_back(root->key);


if (root->key == key) 
return true;
//递归访问左子树或右子树
bool find = (findpath(root->left, path, key) || findpath(root->right, path, key));


if (find)
return true;
//如果在这个节点下没有找到就弹出
path.pop_back();
return false;
}
//找到从root到节点值为key的路径,存储在顺序表中。
int findLCA(Node * root, int key1, int key2)
{
vector<int> path1;
vector<int> path2;


bool find1 = findpath(root, path1, key1);
bool find2 = findpath(root, path2, key2);


if (find1 && find2)
{
int val;
for (int i = 0; i<path1.size(); i++){
if (path1[i] != path2[i]){
break;
}
else
val = path1[i];
}
return val;
}
return -1;
}

方法二:

从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是祖先节点。 

如果都不匹配,则分别递归左、右子树,如果有n1或n2出现在左子树,并且另一个出现在右子树,则root就是祖先节点

 如果两个key都出现在左子树,则说明祖先节点在左子树中,否则在右子树。

递归算法:

#pragma once

#include <iostream>
#include<assert.h>
using namespace std;


struct Node
{
struct Node *left;
struct Node *right;
int key;
};
Node* newNode(int key)
{
Node *temp = new Node;
temp->key = key;
temp->left = NULL;
temp->right = NULL;
return temp;
}

// 判断n1和n2在不在树中
Node* _Find(int x, Node* root)
{
if (root == NULL)
{
return NULL;
}
if (root->key == x)
{
return root;
}
Node* ret = _Find(x, root->left);
if (ret)
{
return ret;
}
return _Find(x, root->right);
}


struct Node *findLCA(struct Node* root, int n1, int n2)
{

if (root == NULL)
return NULL;

//如果一个节点是另一个根结点,则返回这个节点
if (root->key == n1 || root->key == n2)
return root;

// 分别在左右子树查找
Node *left_lca = findLCA(root->left, n1, n2);
Node *right_lca = findLCA(root->right, n1, n2);

// 如果都返回非空指针 Non-NULL, 则说明两个节点分别出现了在两个子树中,则当前节点肯定为祖先节点
if (left_lca && right_lca) 
return root;


// 如果一个为空,在说明祖先节点在另一个子树
return (left_lca != NULL) ? left_lca : right_lca;
}
//测试
void test()
{
// 构造上面图中的树
Node * root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->right->left->left = newNode(8);
int n1 = 4; 
int n2 = 5;
Node* ret1 = _Find(n1, root);
Node* ret2 = _Find(n2, root);
if (ret1 == NULL || ret2 == NULL)
return;
cout << "LCA(4, 5) = " << findLCA(root, 4, 5)->key;
/*cout << "\nLCA(4, 6) = " << findLCA(root, 4, 6)->key;
cout << "\nLCA(3, 4) = " << findLCA(root, 3, 4)->key;
cout << "\nLCA(2, 4) = " << findLCA(root, 2, 4)->key;
cout << "\nLCA(8, 7) = " << findLCA(root, 8, 7)->key;*/
cout << endl;
}

树:


编译结果:


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值