1. 程式人生 > >求二叉樹中兩個節點的最近公共祖先結點

求二叉樹中兩個節點的最近公共祖先結點

二叉樹是搜尋二叉樹

1、原理:二叉搜尋樹是排序過的 ,位於左子樹的結點都比父結點小,位於右子樹的結點都比父結點大,我們只需從根節點開始和兩個輸入的結點進行比較,如果當前節點的值比兩個結點的值都大,那麼最低的公共祖先結點一定在該結點的左子樹中,下一步開遍歷當前結點的左子樹。如果當前節點的值比兩個結點的值都小,那麼最低的公共祖先結點一定在該結點的右子樹中,下一步開遍歷當前結點的右子樹。這樣從上到下找到第一個在兩個輸入結點的值之間的結點。

2、實現程式碼

BinaryNode* CreateBinaryTree(int* array, int length)
{
	BinaryNode* root = new BinaryNode(array[0]);
	BinaryNode* pTemp = NULL;
	for (int idx = 1; idx < length; idx++)
	{
		BinaryNode* pCur = root;
		//尋找插入位置
		while (pCur)
		{
			if (array[idx]<pCur->_value)
			{
				pTemp = pCur;
				pCur = pCur->_left;
			}
			else if (array[idx]>pCur->_value)
			{
				pTemp = pCur;
				pCur = pCur->_right;
			}
			else
				return NULL;
		}
		//插入元素
		pCur = new BinaryNode(array[idx]);
		if (array[idx] < pTemp->_value)
			pTemp->_left = pCur;
		else
			pTemp->_right = pCur;
	}
	return root;
}

//搜素二叉樹尋找最近公共祖先節點
BinaryNode* AncestorTreeNode(BinaryNode* pRoot, BinaryNode* node1, BinaryNode* node2)
{
	if (pRoot == NULL)
		return NULL;
	if (node1 == NULL)
		return node2;
	if (node2 == NULL)
		return node1;
	while (pRoot)
	{
		if (pRoot->_value > node1->_value && pRoot->_value > node2->_value)
			pRoot = pRoot->_left;
		if (pRoot->_value < node1->_value && pRoot->_value < node2->_value)
			pRoot = pRoot->_right;
		else
			return pRoot;
	}
	return NULL;
}
測試用例:
void FunTest1()
{
	BinaryNode* pRoot = NULL;
	int array[] = { 5, 2, 6 };
	int length = sizeof(array) / sizeof(array[0]);
	pRoot = CreateBinaryTree(array, length);
	BinaryNode* node1 = pRoot->_left->_left;
	BinaryNode* node2 = pRoot->_left->_right;
    BinaryNode* pNode = AncestorTreeNode(pRoot, node1, node2);
	if (pNode)
		cout << pNode->_value << endl;
}

二叉樹節點中包含指向父節點的指標

1、原理:如果樹中每個結點都有父結點(根結點除外),這個問題可以轉換成求兩個連結串列的第一個公共結點,假設樹結點中指向父結點的指標是parent,樹的每一個葉結點開始都由一個指標parent串起來的連結串列,每個連結串列的尾結點就是樹的根結點。那麼輸入的這兩個結點位於連結串列上,它們的最低公共祖先結點剛好是這兩個連結串列的第一個公共結點。 2、實現程式碼
int Hight(BinaryNode* root, BinaryNode* node)
{
	int len = 0;
	while (node)
	{
		len++;
		node = node->_parent;
	}
	return len;
}
BinaryNode* GetLastCommonAncestor(BinaryNode* root, BinaryNode* node1, BinaryNode* node2)
{

	if (root == NULL || node1 == NULL || node2 == NULL)
		return NULL;

	int len1 = Hight(root, node1);//一個連結串列的高度
	int len2 = Hight(root, node2);//另一個連結串列的高度
	//尋找兩個連結串列的第一個交點
	while (len1 != len2)
	{
		if (len1 < len2)
			len2--;
		else
			len1--;
	}

	while (node1 && node2 && node1 != node2)
	{
		node1 = node1->_parent;
		node2 = node2->_parent;
	}

	if (node1 == node2)
		return node1;
	else
		return NULL;
}
測試用例
void FunTest()
{
	BinaryNode* root = new BinaryNode(1);
	BinaryNode* cur = root;
	queue<BinaryNode*> q;
	BinaryNode* top = NULL;

	q.push(root);
	for (int i = 2; i <= 7; i++)
	{
		if (!q.empty())
		{
			top = q.front();
			if (cur == top->_left)
			{
				cur = new BinaryNode(i);
				top->_right = cur;
				cur->_parent = top;
				q.pop();
			}
			else
			{
				cur = new BinaryNode(i);
				top->_left = cur;
				cur->_parent = top;
			}
			q.push(cur);
		}
	}
	BinaryNode* node1 = root->_left->_left;
	BinaryNode* node2 = root->_left->_right;
	BinaryNode* ancestor = GetLastCommonAncestor(root, node1, node2);
	if (ancestor)
		cout << ancestor->_value << endl;
	else
		cout << "沒有公共祖先" << endl;
}

二叉樹是普通二叉樹, 沒有指向父結點的指標

1、原理:在二叉樹根結點 的左子樹和右子樹中分別找輸入的兩個結點,如果兩個結點都在左子樹,遍歷當前結點的左子樹,如果兩個結點都在右子樹,遍歷當前結點的右子樹,直到一個在當前結點的左子樹,一個在當前結點的右子樹,返回當前結點就是最低的公共祖先結點。 2、實現程式碼
bool IsNodeInTree(BinaryNode* pRoot, BinaryNode* pNode)
{
	if (pRoot == NULL || pNode == NULL)
		return false;
	if (pNode == pRoot)
		return true;
	if (IsNodeInTree(pRoot->_left, pNode) || IsNodeInTree(pRoot->_right, pNode))
		return true;
	return false;
}
BinaryNode* GetCommonAncestor(BinaryNode* pRoot, BinaryNode* node1, BinaryNode* node2)
{
	if (pRoot == NULL)
		return NULL;
	if (node1 == pRoot && IsNodeInTree(pRoot, node2) || node2 == pRoot && IsNodeInTree(pRoot, node1))
		return pRoot;

	bool node1left = IsNodeInTree(pRoot->_left, node1);
	bool node1right = IsNodeInTree(pRoot->_right, node1);
	bool node2left = IsNodeInTree(pRoot->_left, node2);
	bool node2right = IsNodeInTree(pRoot->_right, node2);
	if (node1left && node2right || node1right && node2left)
		return pRoot;
	if (node1left && node2left)
		return GetCommonAncestor(pRoot->_left, node1, node2);
	if (node1right && node2right)
		return GetCommonAncestor(pRoot->_right, node1, node2);
	return NULL;
}
測試用例
void FunTest3()
{
	BinaryNode* root = new BinaryNode(1);
	BinaryNode* cur = root;
	queue<BinaryNode*> q;
	BinaryNode* top = NULL;

	q.push(root);
	for (int i = 2; i <= 7; i++)
	{
		if (!q.empty())
		{
			top = q.front();
			if (cur == top->_left)
			{
				cur = new BinaryNode(i);
				top->_right = cur;
				cur->_parent = top;
				q.pop();
			}
			else
			{
				cur = new BinaryNode(i);
				top->_left = cur;
				cur->_parent = top;
			}
			q.push(cur);
		}
	}
	BinaryNode* node1 = root->_left->_left;
	BinaryNode* node2 = root->_left->_right;
	BinaryNode* ancestor = GetCommonAncestor(root, node1, node2);
	if (ancestor)
		cout << ancestor->_value << endl;
	else
		cout << "沒有公共祖先" << endl;
}
標頭檔案和結點的結構體
#include<iostream>
#include<queue>
using namespace std;

struct BinaryNode
{
	BinaryNode* _left;
	BinaryNode* _right;
	BinaryNode* _parent;
	int _value;

	BinaryNode(const int& value)
		:_value(value)
		, _left(NULL)
		, _right(NULL)
		, _parent(NULL)
	{}
};







相關推薦

節點最近公共祖先(三叉鏈,搜尋,普通

求二叉樹中兩個節點的最近公共祖先。 要求:分別考慮以下三種情況        1、二叉樹每個節點有parent(三叉鏈)        2、二叉樹是搜尋二叉樹。        3、就是普通二

節點最近公共祖先結點

二叉樹是搜尋二叉樹 1、原理:二叉搜尋樹是排序過的 ,位於左子樹的結點都比父結點小,位於右子樹的結點都比父結點大,我們只需從根節點開始和兩個輸入的結點進行比較,如果當前節點的值比兩個結點的值都大,那麼最低的公共祖先結點一定在該結點的左子樹中,下一步開遍歷當前結點的左子樹。如

節點最近公共祖先節點

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<vector> using std::cin; using std::cout; usi

ODOA(2) 節點的最大距離(C語言實現)

問題描述; 如果我們把二叉樹看成一個圖,父子節點之間的連線看成是雙向的,我們姑且定義"距離"為兩節點之間邊的個數。寫一個程式求一棵二叉樹中相距最遠的兩個節點之間的距離。 演算法很容易想得到: 如果根節點的左子樹或右子樹為空,那麼最大距離即為樹的深度否則,最大距離等於

節點最遠的距離

一說到二叉樹,就有很多題目,今天在程式設計之美中看到了二叉樹中兩個節點最遠的距離。所以給想借機寫一篇部落格。 在開始之前,我們先想想,兩個最常節點的最遠距離是怎麼樣的? 情況一:最大距離可能一個在左子

節點的最小公共祖先(LCA)

題目要求:求二叉樹中兩個節點p,q的最低公共祖先節點 首先,題目中沒有明確說明節點的結構,所以思考了一會然後問面試官節點有沒有父指標,面試官說有沒有父指標有影響嗎?我說有,然後他笑著說你來說說看。當時,只做出來有父指標的情況,沒有父指標的情況壓根想不出來。後

程式設計師面試100題之十六 節點最近公共節點

                這個問題可以分為三種情況來考慮:情況一:root未知,但是每個節點都有parent指標此時可以分別從兩個節點開始,沿著parent指標走向根節點,得到兩個連結串列,然後求兩個連結串列的第一個公共節點,這個方法很簡單,不需要詳細解釋的。情況二:節點只有左、右指標,沒有parent

《程式設計師面試金典》--尋找節點的第一公共祖先(三種情況)

/**************************************************************************************************

搜尋節點最近公共祖先

搜尋二叉樹中兩個節點的最近公共祖先 Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. According to the

資料結構演算法題/節點最近公共節點

這個問題可以分為三種情況來考慮: 情況一:root未知,但是每個節點都有parent指標 此時可以分別從兩個節點開始,沿著parent指標走向根節點,得到兩個連結串列,然後求兩個連結串列的第一個公共節點,這個方法很簡單,不需要詳細解釋的。 情況二:節點只有左、右指標,沒有parent指標,roo

節點的最低公共節點

問題描述 構建一棵二叉樹(不一定是二叉查詢樹),求出該二叉樹中某兩個結點的最低公共父結點。借用一張圖如下: 最低公共父結點的思路 遞迴,首先從樹根開始考慮: ①結點A 和 結點B 要麼都在樹根的左子樹中;②要麼都在樹根的右子樹中;③要麼一個在左子樹中

節點最近公共祖先(leetcode)

leetcode題目地址 二叉樹構造 TreeNode* t1 = new TreeNode(3); TreeNode* t2 = new TreeNode(5); TreeNode* t3 = new TreeNode(1);

問題——尋找節點最近公共祖先

此題大概分為3種情況: 1、節點中無parent,但提供了root (1)、此種情況又分為兩種,開闢空間,使用容器來儲存路徑,將其轉換為求連結串列公共節點的問題,時間複雜度為O(N),空間複雜度為O(N) (2)、不開闢空間,在節點的左右子樹上尋找兩個節點

節點最近公共節點

轉載:http://blog.csdn.net/hackbuteer1/article/details/8022138# 這個問題可以分為四種情況來考慮:情況一:root未知,但是每個節點都有parent指標此時可以分別從兩個節點開始,沿著parent指標走向根節點,得到兩

節點最近公共祖先節點方法全集

一.如果資料結構為三叉連結串列,即含有指向父節點的指標: Node * NearestCommonAncestor(Node * root,Node * p,Node * q) { Node *

尋找節點最近公共祖先——迅雷筆試歸來

      迅雷的筆試可真讓人煎熬啊,題量很大,而且考試時間是三個小時。不過迅雷的題目質量很高,既考查了基礎知識又不乏高難的資料結構和演算法題目。下面和大家分享兩道演算法程式設計題,程式碼沒有在編譯器上除錯,可能會出現一點小bug,感興趣的朋友可以編譯除錯一下。 題目1:將

3.10 調整搜尋錯誤的節點

【題目】:   一棵二叉樹原本是搜尋二叉樹,但是其中有兩個節點調換了位置,使得這棵二叉樹不再是搜尋二叉樹,請找到這兩個錯誤節點並返回。已知二叉樹中所有節點的值都不一樣,給定二叉樹的頭節點head,返回一個長度為2的二叉樹節點型別的陣列errs,errs[0]表示一個錯誤節點,errs[1]表示另一個錯誤節點

利用棧節點最近共同祖先(無父節點指標)

最近的資料結構課剛教完二叉樹,昨晚在做學院自己弄的一個整合環境上的資料結構題目時,看到一個比起其他二叉樹簡單遍歷、或者計算葉子或者深度看起來難一點的題目。就是最近共同祖先節點問題(NCA-nearest common ancestor)。 想了挺久終於用遞迴把它解決了。但

滿排序任意三節點最低公共節點

#include <iostream> using namespace std; int tree[1024*1024]; int k; int a,b,c; int power2(int n) { int i=1; int j; fo

任意結點的距離

case itl wid get ren return roo [] fall 求二叉樹中任意兩個結點的距離實現步驟:計算跟到第一個結點的距離;計算跟到第二個結點的距離;計算lca;計算跟到lca結點的距離;結果為(1) + (2) - 2 * (4),因為重復計算了兩次的