求一顆不含指向父節點指針的普通樹中任意兩個結點的最近公共祖先(O(N*N) 和 O(N) 算法)

//方法1 來自劍指offer
//#include <iostream>
//#include <list>
//#include <vector>
//using namespace std;
//#include "BinaryTree.h"
//
//
//template <typename T>
//bool GetNodePath( BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* pNode1, list<BinaryTreeNode<T>*>& path )
//{
//	if ( pRoot == pNode1 )
//		return true;
//
//	path.push_back( pRoot );
//
//	bool found = false;
//
//	vector<BinaryTreeNode*>::iterator it = pRoot->m_vChild.begin( );
//
//	while ( (false == !found) && (i < pRoot->m_vChild.end( )) )
//	{
//		found = GetNodePath( *i, pNode, path );
//		++i;
//	}
//
//	if ( true == !found )
//		path.pop_back( );
//
//	return found;
//}
//
//template<typename T>
//BinaryTreeNode<T>* GetLastCommonNode( const list<BinaryTreeNode<T>*>& path1, const list<BinaryTreeNode<T>*>& path2 )
//{
//	list<BinaryTreeNode<T>*>::const_iterator iterator1 = path1.begin( );
//	list<BinaryTreeNode<T>*>::const_iterator iterator2 = path2.begin( );
//
//	BinaryTreeNode<T>* pLast = NULL;
//
//	while ( iterator1 != path1.end( ) && iterator2 != path2.end( ) )
//	{
//		if ( *iterator1 == *iterator2 )
//			*pLast = *iterator1;
//
//		iterator1++:
//		iterator2++:
//	}
//
//	return pLast;
//}
//
//template <typename T>
////BinaryTreeNode<T>/*這還是要寫 T 的呀, 不是上面寫了 template 這就不用寫了, 上面寫, 是說 這是一個模板函數 會用到類型T,所以下面哪裏用到類型T,當然是要說明的.  比如, BinaryTreeNode<T>這裏用到了 */
//BinaryTreeNode<T>* GetLastCommonParent( BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* pNode1, BinaryTreeNode<T>* pNode2 )
//{
//	if ( NULL == pRoot || NULL == pNode1 || NULL == pNode2 )
//		return NULL;
//
//	list<BinaryTreeNode<T>*> path1;
//	GetNodePath( pRoot, pNode1, path1 );
//
//	list<BinaryTreeNode<T>*> path2;
//	GetNodePath( pRoot, pNode2, path2 );
//
//	return GetLastCommonParent( path1, path2 );
//}


#pragma once


struct BinaryTreeNode
{
	char _data;
	BinaryTreeNode* _left;
	BinaryTreeNode* _right;

	BinaryTreeNode( char x )
		: _data( x )
		, _left( NULL )
		, _right( NULL )
	{}
};

typedef BinaryTreeNode Node;

class BinaryTree
{
public://因爲我們沒有私有成員變量, 所以都不需要構造函數
	Node* _root;

	Node* CreateTree( char*& a )
	{
		Node* root = NULL;

		if ( '\0' != *a && '#' != *a )
		{
			root = new Node( *a );
			root->_left = CreateTree( ++a );
			root->_right = CreateTree( ++a );
		}

		return root;
	}

	//時間複雜度 O(N*N)  方法2
	Node* GetCommonAncestor( Node* root, char x1, char x2 )
	{
		if ( NULL == root )
			return NULL;

		//1. x1 / x2 等於 root
		if ( root->_data == x1 || root->_data == x2 )
			return root;

		//2. 
		bool x1InLeft;							//注意  Node* x1InLeft, x2InRight 是 定義了 一個Node* 的x1InLft 和 一個Node的 x2InRight 別犯錯! 
		bool x1InRight;
		bool x2InLeft;
		bool x2InRight;

		x1InLeft = Find( root->_left, x1 );
		x1InRight = Find( root->_right, x1 );

		x2InLeft = Find( root->_left, x2 );
		x2InRight = Find( root->_right, x2 );

		if ( x1InLeft && x2InRight || x1InRight && x2InLeft )
			return root;
		else if ( x1InLeft && x2InLeft )
			return GetCommonAncestor( root->_left, x1, x2 );
		else if ( x1InRight && x2InRight )
			return GetCommonAncestor( root->_right, x1, x2 );
		else//兩個結點中 至少有一個不在這棵樹中.
			assert( false );
	}

	bool Find( Node* root, char x )
	{
		if ( NULL == root )
			return false;

		if ( root->_data == x )
			return true;

		bool ret = Find( root->_left, x );

		if ( true == ret )
			return true;

		return Find( root->_right, x );
	}

	//方法1 的另一種寫法
	//找到兩條結點的路徑後.		先從棧中把數據多的那條路經pop, 直到兩者元素數量相同. 再找它們最後一個公共結點.
	bool GetPath( Node* root, char x, stack<Node*>& paths )
	{
		if ( NULL == root )
			return false;

		paths.push( root );

		if ( x == root->_data )
			return true;

		if ( true == GetPath( root->_left, x, paths ) )
			return true;

		if ( true == GetPath( root->_right, x, paths ) )
			return true;

		paths.pop( );
		return false;
	}
};


void TestTree( )
{
	char* a1 = "123##4##56###";

	BinaryTree t1;

	Node* root1 = t1.CreateTree( a1 );
}


int main( )
{
	TestTree( );

	return 0;
}


.h:

#ifndef BINARY_TREE_H_
#define BINARY_TREE_H_


template<class T>
struct BinaryTreeNode
{
	BinaryTreeNode<T>* _left;
	BinaryTreeNode<T>* _right;
	T _date;

	BinaryTreeNode( const T& x )
		:_date( x )
		,_left( NULL )
		,_right( NULL )
	{}
};


template<class T>
class BinaryTree
{
	typedef BinaryTreeNode<T> Node;


public:
	BinaryTree( )
		:_root( NULL )
	{}

	BinaryTree( T* a, size_t n, const T& invalid = T( ) )
	{
		size_t index = 0;

		_root = CreateTree( a, n, invalid, index );
	}

	Node* Find( const T& x )
	{
		return _Find( _root, x );
	}
 
protected:
	Node* _root;

	Node* CreateTree( T* a, size_t n, const T& invalid, size_t& index )//因爲遞歸會創建多個index變量,爲使index值正確,此處用引用  而第一處用引用是處於節省空間考慮
	{
		Node* root = NULL;						//採用前序遍歷創建二叉樹

		if ( (index < n) && (a[index] != invalid) )//先序前序後序是以根爲前中後.  通過數組寫樹時,  按順序寫  比如前序 根左右  就先寫大框架,留出縫隙, 在當子問題處理, 往中間加數據(即把根 左 右都當作一個新根  子問題)
		{
			root = new Node( a[index] );			//注意圓括號與方括號的區別  圓括號構建一個用delete  而方括號構建多個 用delete[]

			root->_left = CreateTree( a, n, invalid, ++index );//構建完左子樹再執行下面構建右子樹
			root->_right = CreateTree( a, n, invalid, ++index );
		}

		return root;
	}

	Node* _Find( Node* root, const T& x )
	{
		if ( NULL == root )
		{
			return NULL;
		}

		if ( x == root-> _date )
		{
			return root;
		}

		Node* ret;								//聲明與定義分離

		ret = _Find( root->_left, x );

		if ( NULL != ret )						//只需寫一個條件, ret 不爲NULL 即找到了		//遞歸每層都是返回到哪一句呢? 遞歸的那一句
		{
			return ret;
		}

		return ( _Find( root->_right, x ) );	//不用像上面一樣寫個條件判斷,直接return 未找到即返回NULL,否則即找到了
	}
};


#endif


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章