二叉樹(1)

二叉樹節點的結構

class Node{
    int value;
    Node left;
    Node right;
    Node(int data){
        this.valve=data;
        }      
}

要求掌握內容
1.能結合隊列、棧、鏈表、字符串等很多數據結構。
2.需掌握圖的遍歷方式,比如BFS和DFS。
3.需掌握遞歸函數的使用,並自己設計出遞歸過程。
先序、中序和後序遍歷
先序遍歷:中、左、右
中序遍歷:左、中、右
後序遍歷:左、右、中
1
23
4567
先序:1 2 4 5 3 6 7
中序:4 2 5 1 6 3 7
後序:4 5 2 6 7 3 1

遞歸方式實現先序遍歷

public void preOrderRecur(Node head){
     if(head==null){
     return;
     }
     System.out.print(head.valve + " ");
     preOrdeRecur(head.left);
     preOrdeRecur(head.right);
     }

思想:若樹爲空,返回。若不爲空,先打印當前頭結點的值,然後遍歷左子樹,最後遍歷右子樹。

非遞歸方式實現先序遍歷
具體過程:
1.先申請一個新的棧,記爲stack。
2.然後將頭結點head壓入stack中。
3.每次從stack中彈出棧頂節點,記爲cur,然後打印cur節點的值。若cur右孩子不爲空的話,將cur的右孩子先壓入stack中。最後如果cur的左孩子不爲空的話,將cur的左孩子壓入stack中。
4.不斷重複步驟3,直到stack爲空,全部過程結束。

遞歸方式實現中序遍歷

public void preOrderRecur(Node head){
     if(head==null){
     return;
     }
     preOrdeRecur(head.left);
     System.out.print(head.valve + " ");
     preOrdeRecur(head.right);
     }

非遞歸方式實現中序遍歷
具體過程:
1.先申請一個新的棧,記爲stack,申請一個變量cur,初始時令cur等於頭節點。
2.先把cur節點壓入棧中,對以cur節點爲頭的整棵子樹來說,依次把整棵樹的左邊界壓入棧中,即不斷令cur=cur.left,然後重複步驟2。
3.不斷重複步驟2,直到發現cur爲空,此時從stack中彈出一個節點,記爲node。打印node的值,並讓cur=node.right,然後重複步驟2。
4.當stack爲空並且cur爲空時,整個過程結束。

遞歸方式實現後序遍歷

public void preOrderRecur(Node head){
     if(head==null){
     return;
     }
     preOrdeRecur(head.left);
     preOrdeRecur(head.right);
     System.out.print(head.valve + " ");
     }

非遞歸方式實現後序遍歷
方法一:使用兩個棧實現
具體過程:
1.先申請一個新的棧,記爲s1,然後將頭結點壓入s1中。
2.從s1中彈出的節點記爲cur,然後先把cur的左孩子壓入s1中,然後把cur1的右孩子壓入s1中。
3.在整個過程中,每一個從s1中彈出的節點都放進第二個棧s2中。
4.不斷重複步驟2和步驟3,直到s1爲空,過程停止。
5.從s2中以此彈出節點並打印,打印的順序就是後序遍歷的順序了。

方法二:使用一個棧實現
具體過程:
1.先申請一個新的棧,記爲stack。將頭節點壓入stack,同時設置兩個變量h和c。在整個流程中,h代表最近一次彈出並打印的節點,c代表當前stack的棧頂節點,初始時令h爲頭節點,c爲null。
2.每次令c等於當前stack的棧頂節點,但是不從stack中彈出節點,此時分以下三種情況。
(1)如果c的左孩子不爲空,並且h不等於c的左孩子,也不等於c的右孩子,則把c的左孩子壓入stack中。
(2)如果情況1不成立,並且c的右孩子不爲空,並且h不等於c的右孩子,則把c的右孩子壓入stack中。
(3)如果情況1和情況2都不成立,那麼從stack中彈出c並打印,然後令h等於c。
3.不斷重複步驟2,直到stack爲空,全部過程結束。

遞歸方式實現深度遍歷

#include<iostream>
#include<string>
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 preorder(BinaryTreeNode* &T){
     if(T){
         cout<<T->data<<" ";
         preorder(T->Left);
         preorder(T->Right);
     }
 }

void midorder(BinaryTreeNode* &T){
     if(T){      
         midorder(T->Left);
         cout<<T->data<<" ";
         midorder(T->Right);
     }
 }

void postorder(BinaryTreeNode* &T){
     if(T){  
         postorder(T->Left);
         postorder(T->Right);
         cout<<T->data<<" ";
     }
 }

int main(){
     BinaryTreeNode* T;               //聲明一個指向二叉樹根節點的指針               
     createBiTree(T);
     cout<<"二叉樹創建完成!"<<endl;
     cout<<"前序遍歷二叉樹:"<<endl;
     preorder(T);
     cout<<endl;
     cout<<"中序遍歷二叉樹:"<<endl;
     midorder(T);
     cout<<endl;
     cout<<"後序遍歷二叉樹:"<<endl;
     postorder(T);
     return 0;
}

非遞歸方式實現深度遍歷

#include<iostream>
#include<string>
#include<stack>
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 preorder(BinaryTreeNode* &T){
    stack<BinaryTreeNode*> s; 
    s.push(T);
    while(!s.empty()){
        BinaryTreeNode* cur=s.top();
        s.pop();
        cout<<cur->data;
        if(cur->Right!=NULL){
           s.push(cur->Right);
        }
        if(cur->Left!=NULL){
           s.push(cur->Left);
        }
     }
 }

void midorder(BinaryTreeNode* &T){
    stack<BinaryTreeNode*> s;
    BinaryTreeNode* cur=T;
    while(cur!=NULL||!s.empty()){
        while(cur!=NULL){
            s.push(cur);
            cur=cur->Left;
         }
        BinaryTreeNode* node=s.top();
        s.pop();
        cout<<node->data;
        cur=node->Right;
    }
 }

void postorder(BinaryTreeNode* &T){
    stack<BinaryTreeNode*> s1;
    stack<BinaryTreeNode*> s2;
    s1.push(T);
    while(!s1.empty()){
        BinaryTreeNode* cur=s1.top();
        s1.pop();
        s2.push(cur);
        if(cur->Left!=NULL){
            s1.push(cur->Left);
        }
        if(cur->Right!=NULL){
            s1.push(cur->Right);
        }
    }
    while(!s2.empty()){
        BinaryTreeNode* node=s2.top();
        s2.pop();
        cout<<node->data;
    }
 }

int main(){
     BinaryTreeNode* T;               //聲明一個指向二叉樹根節點的指針               
     createBiTree(T);               //abd###ce##fg###
     cout<<"二叉樹創建完成!"<<endl; 
     cout<<"前序遍歷二叉樹:"<<endl;
     preorder(T);
     cout<<endl;
     cout<<"中序遍歷二叉樹:"<<endl;
     midorder(T);
     cout<<endl;
     cout<<"後序遍歷二叉樹:"<<endl;
     postorder(T);
     cout<<endl;
     return 0;
}

總結
不管是遞歸方法還是非遞歸方法,遍歷整棵樹的時間複雜度都是O(N),N爲二叉樹節點數,額外空間複雜度爲O(L),L爲二叉樹的層數。

發佈了48 篇原創文章 · 獲贊 2 · 訪問量 9802
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章