二叉樹按層遍歷
1.針對二叉樹的寬度優先遍歷。
第一步:需要藉助隊列,首先將根節點pRoot入隊;
第二步:當隊列不空時,獲得隊首元素並出隊,賦給pRoot,執行第三步;
第三步:如果pRoot左節點存在,則入隊;如果pRoot右節點存在,則入隊;執行第二步。
#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;
class BinaryTreeNode
{
public:
char data;
BinaryTreeNode *Left;
BinaryTreeNode *Right;
};
//創建二叉樹,順序依次爲中間節點->左子樹->右子樹
void createBiTree(BinaryTreeNode* &T) //這裏加上&意思是傳遞的參數爲指針的引用,括號裏面等價於 BiTreeNode* &T
{ //這樣的意義在於在函數執行過後,傳遞進來的指針會發生改變(引用的作用),不可以去掉&
char c;
cin >> c;
if('#' == c) //當遇到#時,令樹的根節點爲NULL,從而結束該分支的遞歸
T = NULL;
else
{
T = new BinaryTreeNode;
T->data=c;
createBiTree(T->Left);
createBiTree(T->Right);
}
}
void levelorder(BinaryTreeNode* &T){
queue<BinaryTreeNode*> q1;
q1.push(T);
while(!q1.empty()){
BinaryTreeNode* cur=q1.front();
q1.pop();
cout<<cur->data;
if(cur->Left!=NULL){
q1.push(cur->Left);
}
if(cur->Right!=NULL){
q1.push(cur->Right);
}
}
}
int main(){
BinaryTreeNode* T; //聲明一個指向二叉樹根節點的指針
createBiTree(T); //abd###ce##fg###
cout<<"二叉樹創建完成!"<<endl;
cout<<"層次遍歷二叉樹:"<<endl;
levelorder(T);
cout<<endl;
return 0;
}
2.寬度優先遍歷常使用隊列結構。
3.面試中,該類題目常對換行有所要求。
給定一顆二叉樹的頭節點head,請按照現在大家看的的這種格式打印。
要求打印成:
1
2 3
4 5 6
7 8
last:表示正在打印的當前行的最右節點
nlast:表示下一行的最後節點
#include<iostream>
#include<string>
#include<stack>
#include<queue>
using namespace std;
class BinaryTreeNode
{
public:
char data;
BinaryTreeNode *Left;
BinaryTreeNode *Right;
};
//創建二叉樹,順序依次爲中間節點->左子樹->右子樹
void createBiTree(BinaryTreeNode* &T) //這裏加上&意思是傳遞的參數爲指針的引用,括號裏面等價於 BiTreeNode* &T
{ //這樣的意義在於在函數執行過後,傳遞進來的指針會發生改變(引用的作用),不可以去掉&
char c;
cin >> c;
if('#' == c) //當遇到#時,令樹的根節點爲NULL,從而結束該分支的遞歸
T = NULL;
else
{
T = new BinaryTreeNode;
T->data=c;
createBiTree(T->Left);
createBiTree(T->Right);
}
}
void levelorder1(BinaryTreeNode* &T){
queue<BinaryTreeNode*> q1;
q1.push(T);
BinaryTreeNode* last=T;
BinaryTreeNode* nlast=NULL;
while(!q1.empty()){
BinaryTreeNode* cur=q1.front();
q1.pop();
cout<<cur->data;
if(cur->Left!=NULL){
q1.push(cur->Left);
nlast=cur->Left;
}
if(cur->Right!=NULL){
q1.push(cur->Right);
nlast=cur->Right;
}
if(cur==last){
last=nlast;
cout<<endl;
}
}
}
int main(){
BinaryTreeNode* T; //聲明一個指向二叉樹根節點的指針
createBiTree(T); //abd###ce##fg###
cout<<"二叉樹創建完成!"<<endl;
cout<<"層次遍歷二叉樹:"<<endl;
levelorder1(T);
cout<<endl;
return 0;
}
思路:
解決方法是使用2個指針last和nlast,用nlast表示當前正在訪問的結點,用last記錄下一行的最後一個結點。
①從根結點開始,初始時nlast=null,即可以想象成爲在根結點的上面,還沒有訪問任何一個結點,認爲此時的所在行是0行(root的上面一行),令last=root,即表示下一行(第1行)的最後一個結點是root,即nlast=null,last=root(這是規定的,只要初始值規定好,之後就會出現需要的規律);
②將root放入隊列後,循環開始,先從隊列中取出一個結點cur,並先後將cur.left和cur.right放入隊列中;每訪問一個結點,就在將該結點放入隊列之後將nlast指針移動到當前結點,表示正在訪問的結點;
③每次放完之後要進行一個判斷,看當前彈出的結點是否等於last。(彈出的結點就是當前正在遍歷的結點,千萬注意,我們要判斷的是從隊列中彈出的結點是否到達每層的最後一個結點,即判斷正在遍歷的結點是否是每一層的最後一個結點,而不是放入隊列中的結點是否是是每一層的最後一個結點—因爲按層遍歷時結點是按照層的順序從左到右從隊列中彈出來的,因此判斷的是彈出的結點是否是每一層的最後一個結點)一開始彈出的結點是root,顯然成立,當將root.left和root.right放入到隊列中之後,nlast指向了結點③,於是令last=nlast,即以結點③作爲下一層(第2層)的最後一個結點……之後彈出cur=②,壓入④⑤,判斷cur!=last,繼續彈出cur=③,壓入⑥⑦,nlast=⑦,判斷cur==last,於是換行,令last=nlast=⑦,……
即總是先彈出一個結點curà壓入2個子節點left和right同時更新nlastà判斷彈出的結點cur是否等於lastà如果不是,不作處理,繼續循環彈出結點;如果是,進行換行操作,同時更新last爲nlast。
二叉樹的序列化和反序列化
1.二叉樹→字符串(序列化)
2.字符串→二叉樹(反序列化)
序列化的方式:
1.根據先序遍歷序列化
2.根據中序遍歷序列化
3.根據後序遍歷序列化
4.按層序列化
二叉樹被記錄成文件的過程叫作二叉樹的序列化,通過文件內容重建原來二叉樹的過程叫作二叉樹的反序列化。給定一顆二叉樹的頭節點head,並已知二叉樹節點的類型爲32位整型。請設計一種二叉樹序列化和反序列化的方案,並用代碼實現。
先序遍歷二叉樹進行序列化
1.假設序列化結果爲str,初始時str爲空字符串。
2.先序遍歷二叉樹時如果需要空節點,在str末尾加上“#!”。(#表示該節點爲空,!表示一個值的結束,這些特殊字符可以自己設置)
3.如果遇到不爲空的節點,假設節點值爲3,就在str的末尾加上“3!”。
用一個特殊字符表示一個二叉樹節點值的結束的意義。
如果不用特殊符號表示值的結束,則以下兩棵樹的序列化結果爲:123###,說明不用特殊字符表示節點值結束的話,會產生歧義。
先序遍歷反序列化
一個二叉樹通過先序遍歷得到的結果,如何進行反序列化。
把字符串str先變成字符串數組values。
str=“12!3!#!#!#!”
轉爲
values=[“12”、”3”、”#”、”#”、”#”]
1.選擇用什麼樣的遍歷方式序列化,就選擇用什麼樣的方式反序列化。
2.一顆樹序列化的結果是唯一的,唯一的結果生成的二叉樹也是唯一的。
按層遍歷的方式對二叉樹進行序列化
1.用隊列來進行二叉樹的按層遍歷,即寬度優先遍歷。
2.除了訪問節點的順序是按層遍歷之外,對結果字符串的處理,與之前介紹的處理方式一樣。