1. 程式人生 > >二叉樹C++實現資料結構實驗

二叉樹C++實現資料結構實驗

#include <iostream>
#include <string.h>
#include <stack>
#include <queue>
using namespace std;
template<class T>
struct BiNode								//二叉數節點
{
	T data;
	BiNode<T>* lchild, *rchild;

};

template<class T>							//模板類
class BiTree
{
public:
	BiTree();								//預設建構函式
	~BiTree();								//解構函式
	BiNode<T>* GetRoot();					//返回根節點
	void PreOrder(BiNode<T>* node);			//先序遍歷
	void InOrder(BiNode<T>* node);			//中序遍歷
	void PostOrder(BiNode<T>* node);		//後序遍歷
	void LevelOrder(BiNode<T>* node);		//層次遍歷


	//選做非遞迴實現
	void PreOrderNonRec(BiNode<T>* node);	//先
	void InOrderNonRec(BiNode<T>* node);	//中
	void PostOrderNonRec(BiNode<T>* node);	//後


	//選做深度,節點數,葉子節點數,
	int NodesNum(BiNode<T>* node);			//節點數
	int TreeDepth(BiNode<T>* node);			//深度
	int LeafNum(BiNode<T>* node);			//葉子節點數


	//選做交換子樹
	void SwapChild(BiNode<T>* node);		//交換子樹


private:
	BiNode<T>* m_root;						//獲取根節點
	BiNode<T>* Create();					//建立二叉樹
};

template<class T>
BiTree<T>::BiTree()
{
	m_root = new BiNode<T>;
	m_root = Create();
}

template<class T>
BiTree<T>::~BiTree(){}

template<class T>
BiNode<T>* BiTree<T>::Create()				//1. 按先序序列構造一棵二叉連結串列表示的二叉樹T;
{
	char ch=getchar();
	BiNode<T>* pnode;

	if (ch == ' ')
		pnode = NULL;
	else
	{
		pnode = new BiNode<T>;
		pnode->data = ch;
		pnode->lchild = Create();
		pnode->rchild = Create();
	}
	return pnode;
}

template<class T>
BiNode<T>* BiTree<T>::GetRoot()
{
	return m_root;
}

template<class T>
void BiTree<T>::PreOrder(BiNode<T>* node)
{
	if (!node)
		return;
	else
	{
		cout << node->data;
		PreOrder(node->lchild);
		PreOrder(node->rchild);
	}
}

template<class T>
void BiTree<T>::InOrder(BiNode<T>* node)
{
	//前後定根,中序定左右
	if (!node)
		return;
	else
	{
		InOrder(node->lchild);
		cout << node->data;
		InOrder(node->rchild);
	}

}

template<class T>
void BiTree<T>::PostOrder(BiNode<T>* node)
{
	if (!node)
		return;
	else
	{
		PostOrder(node->lchild);
		PostOrder(node->rchild);
		cout << node->data;
	}

}

template<class T>
void BiTree<T>::LevelOrder(BiNode<T>* node)
{
	//層次遍歷需要queue來實現,思路:
	//@1初始化queue
	//	if root為空 返回
	//@2 push(root)
	//@3 while(queue不為空)
	//		s <-- queue.front()
	//		queue.pop()
	//		輸入s.data
	//		if(s的左子樹不空)
	//			s的左子樹入隊
	//		if(s的右子樹不空)
	//			s的右子樹入隊

	queue<BiNode<T>*> q;
	BiNode<T>* s = node;
	if (!s)
		return;
	q.push(s);
	while (!q.empty())
	{
		s = q.front();
		q.pop();
		cout << s->data;
		if (s->lchild)
			q.push(s->lchild);
		if (s->rchild)
			q.push(s->rchild);

	}
}


//先序遍歷非遞迴需要藉助stack s來實現,模擬遞迴呼叫
//總的迴圈邊界是當前節點不為空或者stack不空,
template<class T>
void BiTree<T>::PreOrderNonRec(BiNode<T>* node)
{
	stack<BiNode<T>*> s;
	BiNode<T>* p = node;
	while (p|| !s.empty())
	{
		/*
		@1.每次找當前的節點的左子節點直到左為空,經過的節點入棧,
		@2.然後彈出當前節點,搜尋一次右節點,如果p為空並且s空則退出否則繼續@1
		*/
		while (p)//這裡執行VL
		{
			cout << p->data;//V
			s.push(p);//訪問過的加入棧
			p = p->lchild;//L
		}
		if (!s.empty())//這裡執行R
		{
			p = s.top();
			s.pop();
			p = p->rchild;//R
		}
	}


}

template<class T>
void BiTree<T>::InOrderNonRec(BiNode<T>* node)
{
	//@1 在當前節點p非空時候,將p入棧s,p的左子樹賦給p,保證左子樹都能入棧
	//	p為空時候,也就是左子樹最左邊訪問到了,這時候在棧非空的時候
	//@2 取棧頂給p,輸入p,出棧,這時候最底層的最左邊節點訪問了,將p的右子樹賦給p,重複@1
	stack<BiNode<T>*> s;
	BiNode<T>* p = node;
	while (p|| !s.empty())
	{
		while (p)//這裡執行L
		{
			s.push(p);
			p = p->lchild;
		}
		if (!s.empty())//這裡執行VR
		{
			p = s.top();
			cout << p->data;
			s.pop();
			p = p->rchild;
		}
	}
}

template<class T>
void BiTree<T>::PostOrderNonRec(BiNode<T>* node)
{
	//訪問子節點的條件有兩種
	//1.當前節點的左右節點都為空,可以直接訪問
	//2.前一個被訪問的節點是當前節點的子節點
	//這樣就需要兩個指標,一個指向當前一個指向前一個被訪問的節點
	//然後保證入棧順序是先右再左,(這裡先壓右再壓左,這樣左在上面,就先訪問左)
	if (!node)
		return;
	stack<BiNode<T>*> s;
	s.push(node);
	BiNode<T>* pre = NULL;
	BiNode<T>* cur;
	while (!s.empty())
	{
		cur = s.top();
		if (!cur->lchild&& !cur->rchild ||(pre != NULL) && (pre == cur->lchild || pre == cur->rchild))//上一次訪問的是當前節點的左子樹
		{
			cout << cur->data;
			s.pop();
			pre = cur;//pre是前一個被訪問的節點
		}
		else
		{
			if (cur->rchild)
				s.push(cur->rchild);
			if (cur->lchild)
				s.push(cur->lchild);

		}
	}

}

template<class T>
int BiTree<T>::LeafNum(BiNode<T>* node)
{
	//遞迴思路:找到葉子節點返回值加一,返回值計數
	//2種情況
	//1.節點為空,返回 0,傳遞回去
	//2.每當到達葉子節點,返回 1,傳遞給上一層函式
	if (!node)
		return 0;
	if (!node->lchild&&!node->rchild)
		return 1;
	return LeafNum(node->lchild) + LeafNum(node->rchild);
}

template<class T>
int BiTree<T>::TreeDepth(BiNode<T>* node)
{
	/*
	遞迴思路:
	每個節點都有自己的左右子樹,
	每次返回當前節點左右子樹長度大的那個

	1.如果根節點為空,則深度為0,返回0,遞迴的出口
	2.否則深度至少為1,然後累加他們左右子樹的深度,
	*/
	int LChildDep = 1, RChildDep = 1;
	if (!node)
		return 0;
	LChildDep += TreeDepth(node->lchild);//每次返回之前子樹的長度
	RChildDep += TreeDepth(node->rchild);
	return (LChildDep>RChildDep) ? (LChildDep) : (RChildDep);

}

template<class T>
int BiTree<T>::NodesNum(BiNode<T>* node)
{
	//思路,遞迴遍歷所有節點,如果不是空節點的話,遞迴返回值加1
	if (!node)
		return 0;
	return NodesNum(node->lchild) + NodesNum(node->rchild) + 1;

}

template<class T>
void BiTree<T>::SwapChild(BiNode<T>* node)
{
	//思路,交換所有節點的節點,每個節點走一遍
	if (node)
	{
		swap(node->lchild, node->rchild);
		SwapChild(node->lchild);
		SwapChild(node->rchild);
	}
}


/*

樣例輸入:
ABC  DE G  F    ↙

樣例輸出:
先序建立一棵二叉樹,請輸入節點的值:ABC  DE G  F   
建立完畢.
先序:ABCDEGF
中序:CBEGDFA
後序:CGEFDBA
層序:ABCDEFG
選做題1:採用非遞迴演算法實現二叉樹遍歷
先序:ABCDEGF
中序:CBEGDFA
後序:CGEFDBA
選做題2:求二叉樹的深度/結點數目/葉結點數目
TreeDepth is 5
NodesNum is 7
LeafNum is 3
選做題3:將二叉樹每個結點的左右子樹交換位置。
交換完畢.
先序:ABDFEGC
中序:AFDGEBC
後序:FGEDCBA
層序:ABDCFEG
*/

int main()
{
	cout << "先序建立一棵二叉樹,請輸入節點的值:";
	BiTree<char> bitree;
	cout << "建立完畢." << endl;
	cout << "先序:";
	bitree.PreOrder(bitree.GetRoot());
	cout << endl;
	cout << "中序:";
	bitree.InOrder(bitree.GetRoot());
	cout << endl;
	cout << "後序:";
	bitree.PostOrder(bitree.GetRoot());
	cout << endl;
	cout << "層序:";
	bitree.LevelOrder(bitree.GetRoot());
	cout << endl;
	cout << "選做題1:採用非遞迴演算法實現二叉樹遍歷" << endl;
	cout << "先序:";
	bitree.PreOrderNonRec(bitree.GetRoot());
	cout << endl;
	cout << "中序:";
	bitree.InOrderNonRec(bitree.GetRoot());
	cout << endl;
	cout << "後序:";
	bitree.PostOrderNonRec(bitree.GetRoot());
	cout << endl;
	cout << "選做題2:求二叉樹的深度/結點數目/葉結點數目" << endl;
	cout << "深度為    : " << bitree.TreeDepth(bitree.GetRoot()) << endl;
	cout << "結點數目  : " << bitree.NodesNum(bitree.GetRoot()) << endl;
	cout << "葉結點數目: " << bitree.LeafNum(bitree.GetRoot()) << endl;
	cout << "選做題3:將二叉樹每個結點的左右子樹交換位置。" << endl;
	bitree.SwapChild(bitree.GetRoot());
	cout << "交換完畢." << endl;
	cout << "先序:";
	bitree.PreOrder(bitree.GetRoot());
	cout << endl;
	cout << "中序:";
	bitree.InOrder(bitree.GetRoot());
	cout << endl;
	cout << "後序:";
	bitree.PostOrder(bitree.GetRoot());
	cout << endl;
	cout << "層序:";
	bitree.LevelOrder(bitree.GetRoot());
	cout << endl;
	system("pause");
}