1. 程式人生 > >二叉樹的基本操作C++

二叉樹的基本操作C++

二叉樹實現
1.建立二叉樹
2.遞迴輸出二叉樹
2.1遞迴先序輸出
2.2遞迴中序輸出
2.3遞迴後序輸出
3.非遞迴輸出
3.1非遞迴先序輸出
3.2非遞迴中序輸出
3.3非遞迴後序輸出
4.層次遍歷二叉樹
5.求樹高
6.求樹葉子節點
7.按值查詢對應節點,輸出左孩子結點值和右孩子結點值

8.計算所有節點數

/*
二叉樹實現
	1.建立二叉樹
	2.遞迴輸出二叉樹
		2.1遞迴先序輸出
		2.2遞迴中序輸出
		2.3遞迴後序輸出
	3.非遞迴輸出
		3.1非遞迴先序輸出
		3.2非遞迴中序輸出
		3.3非遞迴後序輸出
	4.層次遍歷二叉樹
	5.求樹高
	6.求樹葉子節點
	7.按值查詢對應節點,輸出左孩子結點值和右孩子結點值
	8.計算所有節點數
*/
#include<iostream>
#include<string>
#include<stack>
#include<deque>
#include<fstream>
using namespace std;

//const int MAX_N = 100;
//資料節點
class Node
{
public:
	char data;//資料
	class Node *lchild;//左節點
	class Node *rchild;//右節點
};

//二叉樹
class Tree
{
public:
	Tree(){}
	~Tree(){}

	//構建二叉樹
	void Create(string name)
	{
		ifstream readfile;
		string str;
		readfile.open(name);
		if (readfile.is_open())
		{
			getline(readfile, str);//讀取一行
		}
		readfile.close();
		CreateNode(str);//構建二叉樹
	}


	//先序遍歷非遞迴演算法
	void Disp()
	{
		if (t == NULL)
		{
			return;
		}
		stack<Node *> m_stack;//定義棧
		m_stack.push(t);
		while (!m_stack.empty())
		{
			Node *p = m_stack.top();//賦值一份當前雙親節點
			cout << p->data << ends;
			m_stack.pop();
			if (p->rchild)//先儲存右子樹,確保先輸出左子樹
			{
				m_stack.push(p->rchild);
			}
			if (p->lchild)//後儲存左子樹
			{
				m_stack.push(p->lchild);
			}
		}
	
	}

	//非遞迴中序遍歷二叉樹
	void DispMid()
	{
		if (t == NULL)
		{
			return;
		}
		Node *p = t;
		stack<Node *>m_stack;
		while (p != NULL || !m_stack.empty())
		{
			while (p != NULL)//一路直走至左下角
			{
				m_stack.push(p);
				p = p->lchild;
			}
			if (!m_stack.empty())
			{
				p = m_stack.top();//備份當前棧頂地址
				m_stack.pop();
				cout << p->data << ends;
				p = p->rchild;
			}
		}
	}

	//非遞迴後序遍歷二叉樹
	void DispBehid()
	{
		if (t == NULL)
		{
			return;
		}
		Node *pre = NULL, *p = t;
		stack<Node *>m_stack;
		while (p != NULL || !m_stack.empty())
		{
			while (p != NULL)//一路直走至左下角
			{
				m_stack.push(p);
				p = p->lchild;
			}
			p = m_stack.top();
			//右子樹為空或者已訪問,輸出當前節點
			if (p->rchild == NULL || p->rchild == pre)
			{
				cout << p->data << ends;
				pre = p;//將當前結點地址賦值pre作為下一次判斷標誌,防止重複訪問
				m_stack.pop();
				p = NULL;//p賦值空以便訪問右子樹
			}
			else
			{
				p = p->rchild;//訪問子樹的右子樹
			}
		}
	}

	//層次遍歷
	void level_display()
	{
		if (t == NULL)
		{
			return;
		}
		deque<Node *>m_qu;//定義佇列
		m_qu.push_back(t);//樹根入佇列
		while (!m_qu.empty())
		{
			Node *p = m_qu.front();//拷貝當前對頭
			cout <<p->data << ends;//輸出
			m_qu.pop_front();
			if (p->lchild)//左孩子入佇列
			{
				m_qu.push_back(p->lchild);
			}
			if (p->rchild)//右孩子入佇列
			{
				m_qu.push_back(p->rchild);
			}
		}
	}

	//遞迴先序遍歷輸出二叉樹
	void display()
	{
		cout << "遞迴先序:";
		output(t);
		cout << endl;
	}

	//遞迴中序遍歷輸出二叉樹
	void displayMid()
	{
		cout << "遞迴中序:";
		outputMid(t);
		cout << endl;
	}

	//遞迴後序遍歷輸出二叉樹
	void displayBhind()
	{
		cout << "遞迴後序";
		outputBhind(t);
		cout << endl;
	}
	//二叉樹高度
	void Height()
	{
		int height = get_height(t);
		cout << "Height: " << height << endl;
	}

	//輸出葉子節點值
	void display_leaf()
	{
		cout << "Leaves: ";
		output_leaf(t);
		cout << endl;
	}

	//查詢二叉樹中值data域為elem的節點
	void find_node(char elem)
	{
		Node *res = NULL;
		res = find_node(t, elem, res);
		if (res != NULL)
		{
			cout << "nice." << endl;
			if (res->lchild)
			{
				cout << "left child:";
				cout << leftchild(res)->data << endl;
			}
			if (res->rchild)
			{
				cout << "right child:";
				cout << rightchild(res)->data << endl;
			}
		}
		else
		{
			cout << "NO." << endl;
		}
	}

	//計算節點數
	void nodes_count()
	{
		int sum;
		if (t == NULL)//若為空,則0個節點
		{
			sum = 0;
		}
		else
		{
			sum = node_count(t);
			cout << "Total Nodes:" << sum + 1 << endl;
		}
	}
private:
	Node *t;

	//構建二叉樹
	void CreateNode(string str)
	{
		stack<Node *> m_stack;
		Node *p;
		int k;
		while (str.length() != 0)
		{
			//若當前為'(',將雙親節點推入棧,下一位儲存的p值作為左節點處理
			if (str[0] == '(')
			{
				m_stack.push(p); k = 1;
			}
			//為右括號則棧頂退出一位
			else if (str[0] == ')')
			{
				m_stack.pop();
			}
			//為',',則下一個字元作右節點處理
			else if (str[0] == ',')
			{
				k = 2;
			}
			//儲存值用作雙親結點
			else
			{
				p = (Node *)malloc(sizeof(Node));
				p->data = str[0];
				p->lchild = p->rchild = NULL;
				//樹根為空時,將第一個節點作為樹根並賦值給私有成員變數
				if (t == NULL)
				{
					t = p;
				}
				//樹根不為空
				else
				{
					if (k == 1)//作為左節點處理,將棧中雙親節點的左指標指向當前節點
					{
						m_stack.top()->lchild = p;
					}
					else//作為右節點處理
					{
						m_stack.top()->rchild = p;
					}
				}
			}
			//重構串,除去首字元,並將串長度減小1
			str.assign(str.substr(1, str.length() - 1));
		}
	}

	//遞迴先序遍歷輸出二叉樹
	void output(Node *t)
	{
		if (t != NULL)//當樹根不為空時
		{
			cout << t->data;//輸出
			if (t->lchild != NULL || t->rchild != NULL)//左/右結點不為空時遞迴到下一層
			{
				cout << "(";
				output(t->lchild);
				if (t->rchild != NULL)//當左節點遍歷結束後,左節點遞迴返回一層,遞迴右節點
				{
					cout << ",";
				}
				output(t->rchild);
				cout << ")";
			}
		}
	}

	//遞迴中序遍歷二叉樹
	void outputMid(Node *t)
	{
		if (t == NULL)//空則返回
		{
			return;
		}
		else
		{
			cout << "(";
			outputMid(t->lchild);//遞迴左孩子節點
			if (t->rchild != NULL)
			{
				cout << ",";
			}
			cout << t->data;//輸出
			outputMid(t->rchild);//遞迴右孩子結點
			cout << ")";
		}
	}

	//遞迴後序遍歷輸出二叉樹
	void outputBhind(Node *t)
	{
		if (!t)//空則返回
		{
			return;
		}
		else
		{
			cout << "(";
			outputBhind(t->lchild);//遞迴左孩子節點
			if (t->rchild != NULL)
			{
				cout << ",";
			}
			outputBhind(t->rchild);//遞迴右孩子結點
			cout << t->data;//輸出
			cout << ")";
		}
	}
	//求樹高
	int get_height(Node *t)
	{
		int leftheight, rightheight;
		if (t == NULL)//遞迴至不存在子節點時返回0
		{
			return 0;
		}
		else
		{
			leftheight = get_height(t->lchild);//遞迴求左子樹高度
			rightheight = get_height(t->rchild);//遞迴其右子樹高度
			return leftheight > rightheight ? leftheight+1 : rightheight+1;//遞迴返回時返回最大值
		}
	}

	//查詢左節點
	Node *leftchild(Node *p)
	{
		return p->lchild;
	}

	//查詢右節點
	Node *rightchild(Node *p)
	{
		return p->rchild;
	}

	//輸出葉子節點
	void output_leaf(Node *t)
	{
		if (t != NULL)//樹根不為空時
		{
			//當前節點沒有子節點時輸出節點資料
			if (t->lchild == NULL&&t->rchild == NULL)
			{
				cout << t->data << ends;
			}
			output_leaf(t->lchild);//遞迴左子樹
			output_leaf(t->rchild);//遞迴右子樹
		}
	}

	//查詢二叉樹中值data域為elem的節點

	Node * find_node(Node *t, char elem, Node *res = NULL)
	{
		//Node *res = NULL;
		if (t == NULL)//若當前節點為空,則返回結束
		{
			return NULL;
		}
		else
		{
			if (t->data == elem)//若找到值,返回地址
			{
				//res = t;
				return t;
			}
			else
			{
				if (res == NULL)//若儲存結果的指標不為空,則遞迴查詢左節點
				{
					res = find_node(t->lchild, elem, res);
				}
				if (res == NULL)//若儲存結果的指標不為空,且左節點為搜尋到,則遞迴查詢右節點
				{
					res = find_node(t->rchild, elem, res);
				}
			}
			return res;
		}
	}

	//計算節點數
	int node_count(Node *t)
	{
		int lcount = 0, rcount = 0;
		if (t == NULL)//空則返回
		{
			return 0;
		}
		else
		{
			if (t->lchild != NULL)//遍歷左孩子節點
			{
				lcount = node_count(t->lchild);
				lcount += 1;
			}
			if (t->rchild != NULL)//遍歷右孩子節點
			{
				rcount = node_count(t->rchild);
				rcount += 1;
			}
			return lcount + rcount;//返回當前左右孩子節點數
		}
	}
};


int main()
{
	Tree m_tree;
	m_tree.Create("data");
	m_tree.display();//遞迴先序輸出
	m_tree.displayMid();//遞迴中序輸出
	m_tree.displayBhind();//遞迴後序輸出
	m_tree.Height();//樹高
	m_tree.display_leaf();//葉子節點
	cout << "非遞迴先序:";
	//cout << "Fir:";
	m_tree.Disp();//非遞迴先序遍歷
	cout << endl;
	cout << "非遞迴中序:";
	//cout << "Mid:";
	m_tree.DispMid();//非遞迴中序遍歷
	cout << endl;
	cout << "非遞迴後序:";
	//cout << "Bac:";
	m_tree.DispBehid();//非遞迴後序遍歷
	cout << endl;
	cout << "層次遍歷:";
	m_tree.level_display();//層次遍歷
	cout << endl;
	cout << "Input element:";
	char elem;
	cin >> elem;
	m_tree.find_node(elem);//按節點值查詢
	m_tree.nodes_count();//計算節點數
	return 0;
}
測試結果