二叉樹問題之五
二叉樹
- 分別用遞迴和非遞迴方式實現二叉樹先序、中序和後序遍歷
- 二叉樹的序列化和反序列化
- 遍歷二叉樹的神級方法(Morris遍歷)
- 在二叉樹中找到累加和為指定值的最長路徑長度
- 二叉樹的按層列印與ZigZag列印
分別用遞迴和非遞迴方式實現二叉樹先序、中序和後序遍歷
程式碼
包含測試用例,
#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{