1. 程式人生 > >二叉樹問題之五

二叉樹問題之五

二叉樹

分別用遞迴和非遞迴方式實現二叉樹先序、中序和後序遍歷

程式碼

包含測試用例,

#include
<iostream>
#include<stack> #include<vector> using namespace std; struct treeNode { int val; treeNode* left; treeNode* right; treeNode(int value) { val = value; } }; treeNode* createTree(int a[], int len) { treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len); int i;
for (i = 0; i < len; i++) { tree[i].val = a[i]; tree[i].left = NULL; tree[i].right = NULL; } for (i = 0; i <= len / 2 - 1; i++) { if (2 * i + 1 <= len - 1) tree[i].left = &tree[2 * i + 1]; if (2 * i + 2 <= len - 1) tree[i].right = &tree[2 * i + 2]; } return tree;
} void preOrderRecur(treeNode* root) { if (root == NULL) return; cout << root->val; preOrderRecur(root->left); preOrderRecur(root->right); } void inOrderRecur(treeNode* root) { if (root == NULL) return; inOrderRecur(root->left); cout << root->val; inOrderRecur(root->right); } void postOrderRecur(treeNode* root) { if (root == NULL) return; postOrderRecur(root->left); postOrderRecur(root->right); cout << root->val; } void preOrderNoRecur(treeNode* root) { if (root == NULL) return; stack<treeNode*> treeS; treeNode* cur = root; treeS.push(cur); while (!treeS.empty()) { treeNode* tmp = treeS.top(); cout << tmp->val; treeS.pop(); if (tmp->right != NULL) treeS.push(tmp->right); if (tmp->left != NULL) treeS.push(tmp->left); } cout << endl; } void inOrderNoRecur(treeNode* root) { if (root == NULL) return; stack<treeNode*> treeS; treeNode* cur = root; while (!treeS.empty() || cur != NULL) { if (cur != NULL) { treeS.push(cur); cur = cur->left; } else { treeNode* tmp = treeS.top(); treeS.pop(); cout << tmp->val; cur = tmp->right; } } cout << endl; } //非遞迴實現二叉樹的後序遍歷的過程稍微複雜,用到兩個棧 void postOrderNoRecur(treeNode* root) { if (root == NULL) return; treeNode* cur = root; stack<treeNode*> s1; stack<treeNode*> s2; s1.push(root); while (!s1.empty()) { treeNode* tmp = s1.top(); s1.pop(); s2.push(tmp); if (tmp->left != NULL) s1.push(tmp->left); if (tmp->right != NULL) s1.push(tmp->right); } while (!s2.empty()) { treeNode* tmp1 = s2.top(); s2.pop(); cout << tmp1->val; } cout << endl; } int main() { int input[] = { 1, 2, 3, 4, 5, 6, 7 }; int len = 7; treeNode* root = createTree(input, len); preOrderRecur(root); preOrderNoRecur(root); cout << "========================" << endl; inOrderRecur(root); inOrderNoRecur(root); cout << "========================" << endl; postOrderRecur(root); postOrderNoRecur(root); getchar(); return 0; }

二叉樹的序列化和反序列化

題目

二叉樹被記錄為檔案的過程叫做二叉樹的序列化,通過檔案內容重建原來二叉樹的過程叫作二叉樹的反序列化。給定一顆二叉樹的頭節點head,並已知二叉樹節點值型別為32位整型。設計一種二叉樹序列化和反序列化方案

程式碼

用‘!’表示一個節點的結束,‘#!’表示一直為NULL的節點。

#include<iostream>
#include<vector>
#include<string>
#include<queue>
using namespace std;
struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int value)
	{
		val = value;
	}
};

treeNode* createTree(int a[], int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	int i;
	for (i = 0; i < len; i++)
	{
		tree[i].val = a[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 <= len - 1)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 <= len - 1)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}

string serialize(treeNode* root)
{
	string s;
	if (root == NULL)
	{
		return "#!";
	}
	s += to_string(root->val) + "!";
	s += serialize(root->left);
	s += serialize(root->right);
	return s;
}
//反序列化
treeNode* deSerializeHelper(char **str)
{
	if (**str == '#')
	{
		(*str)++;
		(*str)++;
		return NULL;
	}
	int num = 0;
	while (**str != '\0' && **str != '!')
	{
		num = num * 10 + (**str - '0');
		(*str)++;
	}
	treeNode* root = new treeNode(num);
	if (**str == '\0')
		return root;
	else
		(*str)++;
	root->left = deSerializeHelper(str);
	root->right = deSerializeHelper(str);
	return root;
}

treeNode* deSerialize(string str)
{
	if (str == "#!")
		return NULL;
	int len = str.size();
	char* s = (char*)malloc(sizeof(char));
	memcpy(s, str.c_str(), sizeof(char) * len);
	treeNode* root = deSerializeHelper(&s);
	return root;
}

//判斷兩個樹是否相等
bool isEqual(treeNode* root1, treeNode* root2)
{
	if (root1 == NULL && root2 == NULL)
		return true;
	if (root1 == NULL && root2 != NULL)
		return false;
	if (root1 != NULL && root2 == NULL)
		return false;
	if (root1->val != root2->val)
		return false;
	else
		return isEqual(root1->left, root2->left) && isEqual(root1->right, root2->right);
}

int main()
{
	int input[] = { 1, 2, 3, 4, 5, 6 };
	int len = 6;
	treeNode* root = createTree(input, len);
	string res = serialize(root);
	cout << res << endl;
	treeNode* root1 = deSerialize(res);
	bool res1 = isEqual(root, root1);
	if (res1)
		cout << "Two tree is the same!" << endl;
	else
		cout << "Two tree is not same! May be serial or deserial has a problem" << endl;	
	getchar();
	return 0;
}

遍歷二叉樹的神級方法(Morris遍歷)

題目

給定一顆二叉樹的頭節點head,完成二叉樹的先序、中序和後序遍歷。如果二叉樹節點數為N,要求時間複雜度為O(N),額外空間複雜度為O(1)

程式碼

詳細的解釋過程請參考原書,不再多說

#include<iostream>
using namespace std;
struct treeNode {
	int val;
	treeNode* left;
	treeNode* right;
	treeNode(int value)
	{
		val = value;
	}
};

treeNode* createTree(int a[], int len)
{
	treeNode* tree = (treeNode*)malloc(sizeof(treeNode) * len);
	int i;
	for (i = 0; i < len; i++)
	{
		tree[i].val = a[i];
		tree[i].left = NULL;
		tree[i].right = NULL;
	}
	for (i = 0; i <= len / 2 - 1; i++)
	{
		if (2 * i + 1 <= len - 1)
			tree[i].left = &tree[2 * i + 1];
		if (2 * i + 2 <= len - 1)
			tree[i].right = &tree[2 * i + 2];
	}
	return tree;
}

//morris中序遍歷
void morrisIn(treeNode* root)
{
	if (root == NULL)
		return;
	treeNode* cur1 = root;
	treeNode* cur2 = NULL;
	while (cur1 != NULL)
	{
		cur2 = cur1->left;
		if (cur2 != NULL)
		{
			while (cur2->right != NULL && cur2->right != cur1)
				cur2 = cur2->right;
			if (cur2->right == NULL)
			{
				cur2->right = cur1;
				cur1 = cur1->left;
				continue;
			}
			else
				cur2->right = NULL;
		}
		cout << cur1->val << " ";
		cur1 = cur1->right;
	}
	cout << endl;
}
/*第一步將每個節點左子樹上的最右節點連結到當前節點,第二次
列印之前先將節點進行恢復,這樣可以實現O(1)的空間複雜度,沒有使用
額外的資料結構*/

//morris先序遍歷的情況
//先序遍歷是中序遍歷的簡單改寫,只是列印節點的時機發生了改變
void morrisPre(treeNode* root)
{
	if (root == NULL)
		return;
	treeNode* cur1 = root;
	treeNode* cur2 = NULL;
	while (cur1 != NULL)
	{
		cur2 = cur1->left;
		if (cur2 != NULL)
		{
			while (cur2->right != NULL && cur2->right != cur1)
				cur2 = cur2->right;
			if (cur2->right == NULL)
			{
				cur2->right = cur1;
				cout << cur1->val << " ";
				cur1 = cur1->left;
				continue;
			}
			else
				cur2->right = NULL;
		}
		else
			cout << cur1->val << " ";
		cur1 = cur1->right;
	}
	cout << endl;
}

/*morris後序遍歷略微複雜,實話說後序遍歷的邏輯還沒有理特別清楚,只是簡單地改寫了過來*/
treeNode* reverseEdge(treeNode* from)
{
	treeNode* pre = NULL;
	treeNode* next = NULL;
	while (from != NULL)
	{
		next = from->right;
		from->right = pre;
		pre = from;
		from = next;
	}
	return pre;
}
void printEdge(treeNode* head)
{
	treeNode* tail = reverseEdge(head);
	treeNode* cur = tail;
	while (cur != NULL)
	{
		cout 
            
           

相關推薦

搜索字典實現

搜索二叉樹、源碼分析、中英文字典 利用搜索二叉樹判斷一個單詞是否拼寫正確: 假設把所有單詞都按照搜索樹的性質插入到搜索二叉樹中,我們判斷一個單詞拼寫是否正確就是在樹中查找該單詞是否存在(查找key是否存在)。/***************************************** *D

遍歷:廣度遍歷與深度遍歷

二叉樹,是Python重要的資料結構,依次獲取二叉樹的所有節點,就需要用遍歷的方法來實現. 廣度遍歷 對每一層節點依次訪問,訪問完一層進入下一層,而且每個節點只能訪問一次。以下圖為例,我們要遍歷A,第一層遍歷BCDE,第二次遍歷FGHI,第三層遍歷JKLM. 需要用到佇列(Queue)來

刪除元素

二叉樹刪除一個節點分兩種情況, 第一種:要刪除的節點有左子樹 第二種:要刪除的節點沒有左子樹 假定有以下的二叉樹資料: 現在需要刪除3這個元素,這屬於第一種情況:需要把待刪除的節點的左子樹下的最右邊的資料給拿出來放到3這個位置 ,如果刪除30就是屬於第二種情況了,直接刪除就行了 程式

B紅黑AVL堆積、B-、B+

B樹        即二叉搜尋樹:        1.所有非葉子結點至多擁有兩個子節點(Left和Right);        2.所有結點儲存一個關鍵字;        3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹;        如

種遍歷:前序,中序,後序,非遞迴方法(棧),bfs+佇列)

二叉樹的五種遍歷: 遞迴遍歷:前序,中序,後序,非遞迴方法(棧); 層次遍歷(bfs+佇列); #include <vector> #include <iostream> #include <stack> #include <q

4結點定向

如果兩棵樹的差別僅僅只是各自結點子樹的次序不同時就不作區分,則稱這樣的樹是定向的(oriented),因為我們只考慮結點的相對定向(將這樣的二叉樹視為以結點位導向的樹,即只關心結點的次序,而不關心子樹的

B紅黑AVL堆積、B-、B+總結分析

B樹        即二叉搜尋樹:        1.所有非葉子結點至多擁有兩個兒子(Left和Right);        2.所有結點儲存一個關鍵字;        3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹;        如:        B樹的搜尋,從根結點開

最大搜索

有一棵二叉樹,其中所有節點的值都不一樣,找到含有節點最多 的搜尋二叉子樹,並返回這棵子樹的頭節點. 給定二叉樹的頭結點root,請返回所求的頭結點,若出現多個節點最多的子樹,返回頭結點權值最大的。 分析: 以節點node為頭的樹種,最大搜索二叉樹只可能來自以下兩種情況。 1.如果來自

查詢錯誤節點

一棵二叉樹原本是搜尋二叉樹,但是其中有兩個節點調換了位置,使得這棵二叉樹不再是搜尋二叉樹,請找到這兩個錯誤節點並返回他們的值。保證二叉樹中結點的值各不相同。給定一棵樹的根結點,請返回兩個調換了位置的值,其中小的值在前。 分析:可以進行中序遍歷,那麼數值就是升序,所以如果產生一次降序,那麼第一個錯

完全判斷

分析:可以按照下面條件進行判斷  1. 採用按層遍歷的方式,依次遍歷所有結點  2. 如果當前結點有右孩子沒有左孩子,直接返回false  3. 如果當前結點有左孩子沒有右孩子,那之後的結點必須為葉子結點,否則返回false  4. 如果之前步

判斷平衡

分析:實現求解 二叉樹中每個結點的高度的函式height(BinaryNode );然後先序遍歷二叉樹中的每一個結點node,求出該結點的左子樹高度height(node.left) 和 右子樹高度 height(node.right)。根據左右子樹的高度判斷是否為平衡二叉樹。如果左子樹不是平衡二叉

序列化和反序列化

分析:使用先序遍歷,假設序列化的結果字串為str,初始為str=""。如果遇到null就在str的結尾加”#!”,“#”表示這個節點為空,節點值不存在,"!”表示一個值的結束;如果遇到不為空的節點,在每一個節點值的後面都要加上"!",防止值疊加在一起,因為分層會出錯。反序列化,重構二叉樹,按照先序遍

遍歷方式

一.遞迴進行遍歷  //前序遍歷     public void preOrder(TreeNode root,List<Integer> list){         if(root==null){  

DS--父子結點

題目描述 給定一顆二叉樹的邏輯結構如下圖,(先序遍歷的結果,空樹用字元‘0’表示,例如AB0C00D00),建立該二叉樹的二叉鏈式儲存結構。 編寫程式輸出該樹的所有葉子結點和它們的父親結點 輸入 第一行輸入一個整數t,表示有t個二叉樹 第二行起,按照題目表示的輸入

DS+圖綜合練習--最大路徑

ostream tree ring 一行 {} 等於 content man mil 題目描述 給定一顆二叉樹的邏輯結構(先序遍歷的結果,空樹用字符‘0’表示,例如AB0C00D00),建立該二叉樹的二叉鏈式存儲結構 二叉樹的每個結點都有一個權值,從根結點到每個葉子結點將

層次遍歷(一)

這篇層次遍歷用的是遞迴的方法。比較簡單,主要是領悟思想。其主要思想是通過得出樹的深度來遍歷每一層。請看程式碼//二叉樹層次遍歷 /*遞迴方法*/ //主要難點有2個,1是得到樹的深度,2是迴圈輸出每層

【資料結構】平衡AVL

平衡二叉排序樹 平衡二叉排序樹(Balanced Binary Sort Tree),上一篇部落格【資料結構】二叉排序樹BST講了BST,並且在最後我們說BST上的操作不會超過O(h),既然樹高這麼重要,那麼BBST的研究就是為了使得樹的深度在可接受的範圍內漸近意義下達到O

連結串列的類模板實現

該類模板實現了一個二叉樹的模板類,採用二叉連結串列實現。 定義二叉樹節點類,採用二叉連結串列實現。 [cpp] view plaincopyprint? ///////////////////////// #incl

[資料結構]連結串列的類模板實現

該類模板實現了一個二叉樹的模板類,採用二叉連結串列實現。定義二叉樹節點類,採用二叉連結串列實現。///////////////////////// #include <iostream> #include <cstdlib> #include <

C++實現連結串列

#include "stdafx.h" #include <iostream> #include <deque> using namespace std; template<typename T> struct TreeNode{