二叉树相关面试题--树中两个节点的最低公共祖先

本文探讨了在不同类型的二叉树中寻找两个指定节点的最低公共祖先问题,包括二叉搜索树、三叉链表结构的树及普通二叉树,并提供了具体的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树相关面试题--树中两个节点的最低公共祖先
   第一种情况当这棵树为二叉搜索树时
    这种情况的处理最为简单,当这棵树是二叉搜索树时,就表明其每个节点的数据都是排序过的,左子树的节点都比根节点小,右子树的节点都比根节点是数据大,我们可以根据两个节点的数值与根节点的数值进行比较来确定范围,采用递归算法来使范围不断的缩小。这种方法的实现也相对比较简单。
    主要代码(在处理时要考虑临界值等特殊操作)
    

    第二种情况当这棵树的存储结构是三叉链时
    这种情况也有其处理的特殊性,由于是三叉链,所以我们可以很轻松的由该节点开始向上查找其的父节点和所以祖先节点,所以我们我们可以借助链表或栈来分别存储两个节点的所有祖先节点,然后通过类似查找链表中两个链表的第一个公共节点的操作也可以很容易找到两个节点的最近公共祖先
    主要代码
    
   
    第三种情况就是当这棵树只是一颗普通的二叉树时
    我们可以借助一个函数来得到这两个节点从根节点到此节点的路径,然后借助栈的特性来查找最近的公共祖先。
    其实后两种情况类似,只是查找所有祖先节点的方法不同
    主要代码
    
    
    
    完整代码和测试用例
    
   
#define _CRT_SECURE_NO_WARNINGS 1

#include 
using namespace std;
#include 
#include 
#include 
#include 
struct BinaryTreeNode 
{
	int _data;
	BinaryTreeNode* _left;
	BinaryTreeNode* _right;
	BinaryTreeNode(int data)
		:_data(data)
		, _left(NULL)
		, _right(NULL)
	{}
};

class BinaryTree
{
	typedef BinaryTreeNode Node;
public:
	BinaryTree()
		:_root(NULL)
	{}
	BinaryTree(const int* a, const int size, const int invalid)
	{
		assert(a);
		int index = 0;
		_root = Create(a, size, invalid, index);
	}
	Node* Create(const int* a, const int size, const int invalid, int& index)
	{
		Node* cur = NULL;
		if (index < size&&a[index] != invalid)
		{
			cur = new Node(a[index]);
			cur->_left = Create(a, size, invalid, ++index);
			cur->_right = Create(a, size, invalid, ++index);
		}
		return cur;
	}
	~BinaryTree()
	{
		assert(_root);
		destroy(_root);
	}
	void destroy(Node* root)
	{
		if (root != NULL)
		{
			destroy(root->_left);
			destroy(root->_right);
			delete root;
		}
	}
	void PrevOrder()
	{
		assert(_root);
		_PrevOrder(_root);
		cout << endl;
	}
	void _PrevOrder(Node* root)
	{
		if (root != NULL)
		{
			cout << root->_data<<" ";
			_PrevOrder(root->_left);
			_PrevOrder(root->_right);
		}
	}
	//查找两个节点的最近公共祖先(普通二叉树)
	Node* FindCommonAncestr(Node* x1,Node* x2)
	{
		assert(x1&&x2);
		stack path1;
		stack path2;
		if (GetNodePath(path1, x1) == false)
			return NULL;
		if (GetNodePath(path2, x2) == false)
			return NULL;
		while (path1.size() != path2.size())
		{
			if (path1.size() > path2.size())
				path1.pop();
			else
				path2.pop();
		}
		while (!path1.empty())
		{
			if (path1.top() == path2.top())
				return path1.top();
			path1.pop();
			path2.pop();
		}
	}
	//借助栈来实现,存储从根节点到此节点的路径
	bool GetNodePath(stack &path,Node* node)
	{
		assert(_root);
		if (_GetNodePath(_root, path, node) == true)
			return true;
		else
			return false;
	} 
	bool _GetNodePath(Node* root, stack& path, Node* node)
	{
		if (root == NULL)
			return false;
		path.push(root);
		if (root->_data == node->_data)
			return true;
		if (_GetNodePath(root->_left, path, node) == true)
			return true;
		if (_GetNodePath(root->_right, path, node) == true)
			return true;
		path.pop();
		return false;
	}
private:
	Node* _root;
};


void testf()  
{
	int arr[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', 7 };
	int size = sizeof(arr) / sizeof(arr[0]);
	BinaryTree tree(arr, size, '#');
	tree.PrevOrder();
	if (tree.IsCompleteTree() == true)
		cout << "该树是完全二叉树" << endl;
	else
		cout << "该树不是完全二叉树" << endl;
	BinaryTreeNode* node1 = new BinaryTreeNode(7);
	BinaryTreeNode* node2 = new BinaryTreeNode(6);
	BinaryTreeNode* node=tree.FindCommonAncestr(node1, node2);
	if (node != NULL)
		cout << "最近祖先是" << node->_data << endl;
	else
		cout << "没有公共祖先" << endl;
}

//二叉搜索树
struct BinaryNode
{
	int _data;
	BinaryNode* _left;
	BinaryNode* _right;
	BinaryNode(int data)
		:_data(data)
		, _left(NULL)
		, _right(NULL)
	{}
};
class BinarySearch
{
	typedef BinaryNode Node;
public:
	BinarySearch()
		:_root(NULL)
	{}
	~BinarySearch()
	{
		assert(_root);
		destroy(_root);
	}
	void destroy(Node* root)
	{
		if (root != NULL)
		{
			destroy(root->_left);
			destroy(root->_right);
			delete root;
		}
	}
	void  Insert(int data)
	{
		if (_root == NULL)
		{
			_root = new Node(data);
			return;
		}
		Node* cur = _root;
		Node* parent = NULL;
		while (cur)
		{
			if (cur->_data > data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_data < data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				cout << "无法插入,该节点已存在" << endl;
				return;
			}
		}
		if (parent->_data > data)
			parent->_left = new Node(data);
		else
			parent->_right = new Node(data);
	 
	}
	void PrevOrder()
	{
		assert(_root);
		_PrevOrder(_root);
		cout << endl;
	}
	void _PrevOrder(Node* root)
	{
		if (root != NULL)
		{
			cout << root->_data << " ";
			_PrevOrder(root->_left);
			_PrevOrder(root->_right);
		}
	}
	//在二叉搜索树中查找两个节点的最近公共祖先
	Node* GetCommonAncersor(Node* x1, Node* x2)
	{
		if (_root == NULL)
			return NULL;
		Node* cur=_GetCommonAncersor(_root, x1, x2);
	}
	
	Node* _GetCommonAncersor(Node* root, Node* x1, Node* x2)
	{
		if (root == NULL)
			return NULL;
		if( (x1->_data_data&&x2->_data>root->_data) || (x1->_data > root->_data&&x2->_data < root->_data))
			return root;
		if (x1->_data == root->_data)
			return x1;
		if (x2->_data == root->_data)
			return x2;
		if (x1->_data < root->_data&&x2->_data < root->_data)
			return _GetCommonAncersor(root->_left, x1, x2);
		if (x1->_data > root->_data&&x2->_data >root->_data)
		return	_GetCommonAncersor(root->_right, x1, x2);
	}
private:
	Node* _root;
};
void testSearch()
{
	int arr[] = { 5,3,4,1,7,8,2,6,0,9 };
	int size = sizeof(arr) / sizeof(arr[0]);
	BinarySearch tree;
	for (int i = 0; i < size; ++i)
	{
		tree.Insert(arr[i]);
	}
	tree.PrevOrder();
	BinaryNode* node1 = new BinaryNode(6);
	BinaryNode* node2 = new BinaryNode(7);
	BinaryNode* node = tree.GetCommonAncersor(node1, node2);
	if (node == NULL)
		cout << "没有公共祖先" << endl;
	else
		cout << "公共祖先是: " << node->_data << endl;

}

struct Node
{
	int _data;
	Node* _left;
	Node* _right;
	Node* _parent;
	Node(int data)
		: _data(data)
		, _left(NULL)
		, _right(NULL)
		, _parent(NULL)
	{}
};
class Binary
{
public:
	Binary()
		:_root(NULL)
	{}
	Binary(int* a, int size, int invalid)
	{
		int index = 0;
		_root = Create(a,size,invalid,index);
		_root->_parent = NULL;
	}
	Node* Create(int *a,int size,int invalid,int &index)
	{
		Node* cur = NULL;
		if (index < size&&a[index] != invalid)
		{
			cur = new Node(a[index]);
			cur->_left = Create(a, size, invalid, ++index);
			cur->_right = Create(a, size, invalid, ++index);
			if (cur->_left)
			(cur->_left)->_parent = cur;
			if (cur->_right)
			(cur->_right)->_parent = cur;
		}
		return cur;
	}
	~Binary()
	{
		assert(_root);
		destroy(_root);
	}
	void destroy(Node* root)
	{
		if (root != NULL)
		{
			destroy(root->_left);
			destroy(root->_right);
			delete root;
		}
	}

	Node* GetAncersor(Node* x1, Node* x2)
	{
		if (x1 == NULL || x2 == NULL)
			return NULL;
		list l1;
		list l2;
		Node* parent1 = x1->_parent;
		while (parent1)
		{
			l1.push_front(parent1);
			parent1 = parent1->_parent;
		}
		Node* parent2 = x2->_parent;
		while (parent2)
		{
			l2.push_front(parent2);
			parent2 = parent2->_parent;
		}
		while(l1.size()!= l2.size())
		{
			if (l1.size() > l2.size())
				l1.pop_back();
			else
				l2.pop_back();
		}
		while (!l1.empty() && !l2.empty())
		{
			if (l1.back() == l2.back())
				return l1.back();
			l1.pop_back();
			l2.pop_back();
		}
	}
	Node* Find(int data)
	{
		Node* node = _Find(_root, data);
		if (node!=NULL)
			return node;
		else
			return NULL;
	}
	Node* _Find(Node* root, int data)
	{
		if (root == NULL)
			return NULL;
		if (root->_data == data)
			return root;
		Node* ret = _Find(root->_left, data);
		if (ret)
			return ret;
		return _Find(root->_right, data);
	}

private:
	Node* _root;
};

void testBinary()
{
	int arr[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', 7 };
	int size = sizeof(arr) / sizeof(arr[0]);
	Binary tree(arr, size, '#');
	Node* node1 = tree.Find(3);
	Node* node2 = tree.Find(4);
	Node* node=tree.GetAncersor(node1, node2);
	if (node != NULL)
		cout << "公共祖先是: " << node->_data << endl;
	else
		cout << "没有公共祖先" << endl;
}
int main()
{
	//testf();
	//testSearch();
	testBinary();
	return 0;
}
    
    

    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值