二叉樹完整實現代碼(C++)

爲求方便節點存儲數據類型默認爲char,未以模板形式實現

/*******完整參考示例代碼**** https://www.cnblogs.com/WindSun/p/10859055.html ********完整參考示例代碼****/
#pragma once
#include<iostream>
#include<Stack>
#include<Queue>
using namespace std;
//static int No=0;
struct BNode {
	char data;
	BNode *lChild, *rChild;
	BNode(char a) {
		data = a;
	}
};

class BinaryTree {
	BNode *root;
	int refuseValue;
public:
	BinaryTree() {
		refuseValue = '#';  //輸入停止標記
		root = NULL;
	}
	~BinaryTree() {
		destroy(root);
		root = NULL;
	}
	
///******** 二叉樹的創建 *******///
	///前序遍歷建立二叉樹(帶停止標記)
	void CreateBinTree_UsePreFlag(){
			cout << "please input preOrder number with refuse value: " << endl;
			CreateBinTree_UsePreFlag(root);
	}

	///使用廣義表建立
	void CreateBinTree_UseGenTable() {
		cout << "please input Generalized table: " << endl;
		CreateBinTree_UseGenTable(root);
	}


	///使用先序遍歷和中序遍歷建立
	void CreateBinTree_Pre_mid() {
		char pre[50];
		char mid[50];
		cout << "please input preOrder: " << endl;
		cin >> pre;
		cout << "please input midOrder: " << endl;
		cin >> mid;
		string s1(pre);
		string s2(mid);
		if (s1.length() != s2.length()) {
			cout << "error input!" << endl;
			return;
		}
		int n = s1.length();
		CreateBinTree_Pre_mid(root,pre,mid,n);
	}

	///使用後序遍歷和中序遍歷建立(與上方法相似)
	void CreateBinTree_post_mid() {
		char post[50];
		char mid[50];
		cout << "please input postOrder: " << endl;
		cin >> post;
		cout << "please input midOrder: " << endl;
		cin >> mid;
		string s1(post);
		string s2(mid);
		if (s1.length() != s2.length()) {
			cout << "error input!" << endl;
			return;
		}
		int n = s1.length();
		CreateBinTree_post_mid(root, post, mid, n);
	}

///******* 二叉樹的遍歷 **********///
	///先序遍歷
	void preOrder() {
		cout << "preOrder num: ";
		//遞歸遍歷
	// preOrderPrint_UseRecursion(root);
		//使用棧遍歷
	// preOrderPrint_UseStack1();
		preOrderPrint_UseStack2();
		cout << endl;
	}

	///先序遍歷,廣義表形式
	void preOrder_GenTable() {
		cout << "preOrder num with generalize table: ";
		GenTablePrint(root);
		cout << endl;
	}

	///中序遍歷
	void midOrder() {
		cout << "midOrder num: ";
		///遞歸遍歷
		midOrderPrint_UseRecursion(root);
	   ///使用棧遍歷
	// midOrderPrint_UseStack();
		cout << endl;
	}

	///後序遍歷
	void postOrder() {
		cout << "postOrder num: ";
		//遞歸遍歷
	// postOrderPrint_UseRecursion(root);
	    //使用棧遍歷
		postOrderPrint_UseStack();
		cout << endl;
	}

	///層次遍歷(使用隊列實現)
	void levelOrderPrint() {
		BNode* p = root;
		queue<BNode*> Queue;
		Queue.push(p);
		while (1) {
			if(p->lChild!=NULL)
				Queue.push(p->lChild);
			if (p->rChild != NULL)
				Queue.push(p->rChild);
			cout << p->data << " ";
			Queue.pop();	
			if (Queue.empty())
				break;
			else
				p = Queue.front();
		}
	}

///******* 其餘功能函數 ********///
	///獲取根節點
	BNode* getRoot() {
		return root;
	}

	///獲取二叉樹節點數量
	int size() {  //二叉樹大小
		return size(root);
	}

	///求二叉樹的高度
	int height() {
		//return height_UseStack(root);
		return height_UseRecursion(root);
	}

	///尋找某個節點的父節點
	BNode* parent(BNode* subTree, BNode* current) {  
		if (subTree == NULL)
			return NULL;
		if (subTree->lChild == current || subTree->rChild == current)
			return subTree;
		BNode* p;
		if ((p = parent(subTree->lChild, current)) != NULL)
			return p;
		else
			return parent(subTree->rChild, current);
	}

	///銷燬整個二叉樹,回收空間
	void destroy(BNode *p) {  
		if (p == NULL)
			return;
		else {
			destroy(p->lChild);
			destroy(p->rChild);
			delete p;
			p = NULL;
		}
	}

	///判斷兩個二叉樹是否一致(靜態函數)
	static bool equal(BNode* a, BNode *b) {  
		if (a == NULL&&b == NULL)
			return true;
		if (a != NULL&&b != NULL && (a->data == b->data) && equal(a->rChild, b->rChild) && equal(a->lChild, b->lChild))
			return true;
		else
			return false;
	}

	///判斷是不是徹底二叉樹_方法1 使用層次遍歷,h-1層的最後一個節點序號爲pow(2, level - 1) - 1
	bool isFullBinaryTree_1() {  
		BNode *T = root;
		if (!T)
			return true;
		int front = -1, rear = -1;
		int last = 0, level = 0;
		BNode* a[100];
		stack<int> frontHistory;
		a[++rear] = T;
		BNode* p;
		while (front < rear) {
			p = a[++front];
			if (p->lChild != NULL)
				a[++rear] = p->lChild;
			if (p->rChild != NULL)
				a[++rear] = p->rChild;
			if (front == last) {
				last = rear;
				level++;
				frontHistory.push(front);
			}
		}
		frontHistory.pop();
		//只須要驗證h-1層最後一個節點序號是不是2^(h-1)-1便可!
		return (frontHistory.top()+1) == (pow(2, level - 1) - 1);

	}

	///判斷是不是徹底二叉樹_方法2 利用性質:層次遍歷時出現一個葉子節點則後面的均爲葉子節點(空節點)
	bool isFullBinaryTree_2() {  
		BNode* p = root;
		queue<BNode*> que;
		que.push(p);
		while (!que.empty()) {
			p = que.front();
		    que.pop();
			if (p) {
				que.push(p->lChild);
				que.push(p->rChild);
			}
			else {
				while (!que.empty())
				{
					p = que.front();
					que.pop();
					if (p)
						return false;
				}
			}
		}
		return true;
	}

	///交換節點p下子樹的全部的左右節點
	void swapLeftAndRight(BNode* p) {
	// BNode* p = root;
		if (!p)
			return;
		queue<BNode*> que;
		que.push(p);
		while (!que.empty()) {
			p = que.front();
			que.pop();
			if (p->lChild != NULL)
				que.push(p->lChild);
			if (p->rChild != NULL)
				que.push(p->rChild);
			swap(p);
		}
	}

	///輸出中序遍歷的第i個值,其餘遍歷方法相似
	void valueOfMidOrderNo(int i) {
		int No = 0;
		recursiveMidOrderTemp(root, i,No);
	}

	///遞歸遍歷尋找頂點到節點值爲X的路徑(此爲逆序輸出)
	void printWayToX(char x) {
		//printWayToX_UseRecursion(root, x);
		printWayToX_UseStack(root, x);
		cout << endl;
	}
	

	///找到值爲 x 和 y的最近公共祖先節點。先分別利用後序查找x y的祖先節點存儲在棧中,再在兩個棧中查找最近相同節點!
	char ClosestAncestorNode(char x, char y) {
		if (root == NULL)
			return '#';
		stack<BNode*> s1,s2;
	    AncestorsNodeStack(x,s1);
	    AncestorsNodeStack(y,s2);
		if (s1.empty() || s2.empty())
			return '#';
		int n = 0;
		if (s1.size() >= s2.size())
		{
			n = s1.size() - s2.size();
			for (int i = 0; i < n; i++)
				s1.pop();
		}
		else {
			n = s2.size() - s1.size();
			for (int i = 0; i < n; i++)
				s2.pop();
		}
		while (!s1.empty()) {
			if (s1.top()->data == s2.top()->data)
				return s1.top()->data;
			s1.pop();
			s2.pop();
		}
		return '#';
	}

	///返回存儲節點值爲x的祖先節點的棧
	void AncestorsNodeStack(char x, stack<BNode*> &s) {
		if (root == NULL)
			return;
		BNode* lastPos = NULL;
		s.push(root);
		while (!s.empty()) {
			while (s.top()->lChild != NULL)
			{
				s.push(s.top()->lChild);
				//節點值爲x的節點入棧後,停止該函數
				if (s.top()->data == x)
					return;
			}
			while (!s.empty())
			{
				if (lastPos == s.top()->rChild || s.top()->rChild == NULL)
				{
					lastPos = s.top();
					s.pop();
				}
				else if (s.top() != NULL)
				{
					s.push(s.top()->rChild);
					//查找到x時,停止該函數
					if (s.top()->data == x)
						return;
					break;
				}
			}
		}
	}

	///二叉樹的最大寬度(節點最多的一層的節點數)
	int WidthOfBTree() {
		if (root == NULL)
			return 0;
		int maxWidth = 0;
		int front, rear;
		front = rear = -1;
		int last = 0;
		BNode* p = root;
		BNode* a[100];
		a[++rear] = p;
		while (front < rear) {
			p=a[++front];
			if (p->lChild != NULL)
				a[++rear] = p->lChild;
			if (p->rChild != NULL)
				a[++rear] = p->rChild;

			if (front == last)
			{
				last = rear;
				if (rear - front > maxWidth)
					maxWidth = rear - front;
			}
		}
		return maxWidth;
	}
	
private:
	///先序遍歷
	//1 遞歸遍歷
	void preOrderPrint_UseRecursion(BNode* subTree) {
		if (subTree != NULL) {
			cout << subTree->data << " ";
			preOrderPrint_UseRecursion(subTree->lChild);
			preOrderPrint_UseRecursion(subTree->rChild);
		}
	}

	//2.1 利用棧實現前序遍歷的過程。每次訪問一個結點後,在向左子樹遍歷下去以前,利用這個棧記錄該結點的右子女(若是有的話)結點的地址,
	//以便在左子樹退回時能夠直接從棧頂取得右子樹的根結點,繼續其右子樹的前序遍歷。
	void preOrderPrint_UseStack1() {
		stack<BNode*> s;
		BNode* p=root;
		s.push(NULL);
		while (p != NULL) {
			cout << p->data << " ";
			if (p->rChild != NULL)
				s.push(p->rChild);
			if (p->lChild != NULL)
			{
				p = p->lChild;   //把當前還未處理的右孩子指針存起來
			}
			else {
				p = s.top();
				s.pop();
			}
		}
		cout << endl;
	}

	//2.2 爲了保證先左子樹後右子樹的順序,在進棧時是先進右子女結點地址,後進左子女結點地址,出棧時正好相反。
	void preOrderPrint_UseStack2() {
		BNode* p = root;
		stack<BNode*> s;
		s.push(p);
		while (!s.empty()) {
			p = s.top();
			s.pop();
			cout << p->data << " ";
			if (p->rChild != NULL)
				s.push(p->rChild);
			if(p->lChild!=NULL)
				s.push(p->lChild);
		}
		cout << endl;
	}

	///中序遍歷
	//1.遞歸進行遍歷
	void midOrderPrint_UseRecursion(BNode* subTree) {
		if (subTree != NULL) {
			midOrderPrint_UseRecursion(subTree->lChild);
			cout << subTree->data << " ";
			midOrderPrint_UseRecursion(subTree->rChild);
		}
	}
	//2.使用棧進行遍歷
	void midOrderPrint_UseStack() {
		BNode* p = root;
		stack<BNode*> s;
		do{
			while (p != NULL) {
				s.push(p);
				p = p->lChild;
			}
			if (!s.empty()) {
				p = s.top();
				s.pop();
				cout << p->data << " ";
				p = p->rChild;
			}
		} while (p != NULL || !s.empty());
			    
	}

	///後序遍歷
	//1.遞歸進行遍歷
	void postOrderPrint_UseRecursion(BNode* subTree) {
		if (subTree != NULL) {
			postOrderPrint_UseRecursion(subTree->lChild);
			postOrderPrint_UseRecursion(subTree->rChild);
			cout << subTree->data << " ";
		}
	}
	//2.使用棧進行遍歷
	void postOrderPrint_UseStack() {
		if (root == NULL)
			return;
		BNode *p = root;
		stack<BNode *> s;
		s.push(p);
		BNode *lastPop = NULL;
		while (!s.empty())
		{
			while (s.top()->lChild != NULL)
				s.push(s.top()->lChild);
			while (!s.empty())
			{
				//右葉子結點 || 沒有右結點
				if (lastPop == s.top()->rChild || s.top()->rChild == NULL)
				{
					cout << s.top()->data << " ";
					lastPop = s.top();
					s.pop();
				}
				else if (s.top()->rChild != NULL)
				{
					s.push(s.top()->rChild);
					break;
				}
			}
		}
	}

	///使用帶停止符的前序遍歷建立二叉樹
	void CreateBinTree_UsePreFlag(BNode* &subTree) { //傳入的指針必定要是引用,不然沒法修改傳入指針的指向位置
		char item;
		if (cin >> item)
		{
			if (item != refuseValue) 
			{
				subTree = new BNode(item);
				CreateBinTree_UsePreFlag(subTree->lChild);
				CreateBinTree_UsePreFlag(subTree->rChild);
			}
			else {
				subTree = NULL;
			}
		}
	}

	///使用廣義表建立二叉樹函數,這裏以「字符」建立二叉樹,以'#'字符表明結束
	void CreateBinTree_UseGenTable(BNode* &BT) {
		stack<BNode*> s;
		BT = NULL;
		BNode *p, *t;    //p用來記住當前建立的節點,t用來記住棧頂的元素
		int k;    //k是處理左、右子樹的標記
		char ch;
		while (1)
		{
			cin >> ch;
			if (ch == refuseValue)
				break;
			switch (ch)
			{
			case '(':    //對(作處理
				s.push(p);
				k = 1;
				break;

			case ')':    //對)作處理
				s.pop();
				break;

			case ',':    //對,作處理
				k = 2;
				break;

			default:
				p = new BNode(ch);    //構造一個結點,!注意要給新節點的左右孩子指針賦空值!
				p->lChild = NULL;
				p->rChild = NULL;
				if (BT == NULL)    //若是頭節點是空
				{
					BT = p;
				}
				else {
					if (k == 1)    //鏈入*t的左孩子
					{
						t = s.top();
						t->lChild = p;
					}
					else    //鏈入*t的右孩子
					{
						t = s.top();
						t->rChild = p;
					}
				}
					
			}
		}
	}

	///前序遍歷和中序遍歷建立二叉樹
	void CreateBinTree_Pre_mid(BNode *&cur, const char *pre, const char *mid, int n) {
		if (n <= 0)
		{
			cur = NULL;
			return;
		}
		int k = 0; 
		while (pre[0] != mid[k]) {
			k++;
		}
		cur = new BNode(mid[k]); //建立結點
		CreateBinTree_Pre_mid(cur->lChild, pre + 1, mid,k);
		CreateBinTree_Pre_mid(cur->rChild, pre + k + 1, mid + k + 1,n-k-1);
	}

	///後序遍歷和中序遍歷建立二叉樹
	void CreateBinTree_post_mid(BNode* &cur, const char *post, const char *mid, int n) {
		if (n <= 0)
		{
			cur = NULL;
			return;
		}
		int k = 0;
		while (post[n - 1] != mid[k]) {
				k++;
		}
		cur = new BNode(mid[k]);
		CreateBinTree_post_mid(cur->lChild, post, mid, k);
		CreateBinTree_post_mid(cur->rChild, post + k, mid + k+1,n-k-1);
	}

	///節點p開頭的子樹節點數目
	int size(BNode* p) {
		if (p == NULL)
			return 0;
		return 1 + size(p->lChild) + size(p->rChild);
	}
	
	///節點p開頭的子樹節點高度
	int height_UseRecursion(BNode *p) {
		if (p == NULL)
			return 0;
		int i = height_UseRecursion(p->lChild);
		int j = height_UseRecursion(p->rChild);
		return i > j ? i + 1 : j + 1;
		
	}
	int height_UseStack(BNode *T) {
		if (!T)
			return 0;
		int front = -1, rear = -1;
		int last = 0, level = 0;
		BNode* tree[100];
		tree[++rear] = T;
		BNode* p;
		while (front < rear) {
			p = tree[++front];
			if (p->lChild != 0)
				tree[++rear] = p->lChild;
			if (p->rChild != NULL)
				tree[++rear] = p->rChild;
			if (front == last)
			{
				level++;
				last = rear;
			}
		}

		return level;
	}

	///二叉樹以廣義表形式輸出
	void GenTablePrint(BNode *BT) {
		if (BT != NULL)    //樹爲空時結束遞歸
		{
			cout << BT->data;
			if (BT->lChild != NULL || BT->rChild != NULL)
			{
				cout << '(';
				if (BT->lChild != NULL)
				{
					GenTablePrint(BT->lChild);
				}
				cout << ',';
				if (BT->rChild != NULL)
				{
					GenTablePrint(BT->rChild);
				}
				cout << ')';
			}
		}
	}

	///交換p節點左右孩子
	void swap(BNode* p) {
		BNode* temp = p->lChild;
		p->lChild = p->rChild;
		p->rChild = temp;
		temp = NULL;
	}

	///輸出中序遍歷的第n的節點的值
	void recursiveMidOrderTemp(BNode * subTree, int i, int &No) {//No須要全部遞歸部分共同維護
		if (subTree != NULL) {
			recursiveMidOrderTemp(subTree->lChild, i, No);
			// cout << subTree->data << " ";
			No++;
			if (No == i) {
				cout << subTree->data << endl;
				return;
			}
			if (No > i)
				return;
			recursiveMidOrderTemp(subTree->rChild, i, No);
		}
	}

	///尋找頂點到節點值爲X的路徑(此爲逆序輸出)
	//1.使用遞歸實現
	bool printWayToX_UseRecursion(BNode* p, char x) {
		if (!p)
			return false;
		if (printWayToX_UseRecursion(p->lChild, x) || printWayToX_UseRecursion(p->rChild, x))
		{
			cout << p->data;
			return true;
		}
		else if (p->data == x)
		{
			cout << p->data;
			return true;
		}
		else {
			return false;
		}

	}

	//2.非遞歸遍歷尋找。使用後序遍歷,當查找到x時,棧中元素即爲x的祖節點
	void printWayToX_UseStack(BNode* p, char x) {
		stack<BNode*> s;
		BNode* lastPos = NULL;
		s.push(p);
		while (!s.empty()) {
			while (s.top()->lChild != NULL)
			{
				s.push(s.top()->lChild);
				//節點值爲x的節點入棧後,直接將棧中元素所有輸出而後退出該函數
				if (s.top()->data == x) {
					while (!s.empty()) {
						cout << s.top()->data << " ";
						s.pop();
					}
					return;
				}
			}
			while (!s.empty())
			{
				if (lastPos == s.top()->rChild || s.top()->rChild == NULL)
				{
					lastPos = s.top();
					s.pop();
				}
				else if (s.top() != NULL)
				{
					s.push(s.top()->rChild);
					//查找到x時,直接將棧中元素所有輸出而後退出該函數
					if (s.top()->data == x) {
						while (!s.empty()) {
							cout << s.top()->data << " ";
							s.pop();
						}
						return;
					}
					break;
				}
			}

		}
	}

};


複製代碼
相關文章
相關標籤/搜索