二叉樹(2)

二叉樹按層遍歷
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.除了訪問節點的順序是按層遍歷之外,對結果字符串的處理,與之前介紹的處理方式一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章