樹的遍歷

數的遍歷有4種,分別是前序遍歷,中序遍歷和後序遍歷、層次遍歷。
前序遍歷:根左右
中序遍歷:左根右
後序遍歷:左右根
層次遍歷:第一層節點從左到右,第二層節點從左到右,以此類推。
分享下我怎麼記憶的,只需要記得第一個字表示根的位置,就不會搞混了。另外還要知道,如果只知道前序和後序,是不能唯一確定一棵樹的。

對於每種遍歷,又存在遞歸式和非遞歸式。遞歸式當然好實現,只要簡單的幾行代碼就可以實現;而非遞歸式呢,需要花點功夫,另外非遞歸式的後序遍歷還有點小麻煩。下面來直接看代碼吧

樹的結構體

struct BinaryTreeNode{
    int value;
    BinaryTreeNode *pLeft;
    BinaryTreeNode *pRight;
};

遞歸式

遞歸式前序遍歷

void preOrder(BinaryTreeNode* root){
    if(root==NULL){
        return ;
    }
    else{
        cout<<root->value;
        preOrder(root->pLeft);
        preOrder(root->pRight);     
    }   
}

遞歸式中序遍歷

void InOrder(BinaryTreeNode* root){
    if(root==NULL){
        return ;
    }
    else{
        InOrder(root->pLeft);
        cout<<root->value;
        InOrder(root->pRight);      
    }

}

遞歸式後序遍歷

void postOrder(BinaryTreeNode* root){
    if(root==NULL){
        return ;
    }
    else{
        postOrder(root->pLeft);
        postOrder(root->pRight);    
        cout<<root->value;  
    }   
}

總結:可以看到,我們只需要短短的幾行代碼就可以實現。只需要記住前序遍歷、中序遍歷和後序遍歷的遍歷方式即可。


非遞歸式

非遞歸式前序遍歷

void PreOrder1(BinaryTreeNode* root){
    if (root==NULL){
        return;
    }
    BinaryTreeNode *node = root;
    stack<BinaryTreeNode*>nodelist;
    while(!nodelist.empty()||node!=NULL){
        while(node!=NULL){
            nodelist.push(node);
            cout<<node->value;
            node = node->pLeft;
        }   
        node = nodelist.top();
        nodelist.pop();
        node = node->pRight;
    }
}

非遞歸式中序遍歷

void InOrder1(BinaryTreeNode* root){
    if (root==NULL){
        return;
    }
    BinaryTreeNode *node = root;
    stack<BinaryTreeNode*>nodelist;
    while(!nodelist.empty()||node!=NULL){
        while(node!=NULL){
            nodelist.push(node);
            node = node->pLeft;
        }   
        node = nodelist.top();
        cout<<node->value;
        nodelist.pop();
        node = node->pRight;
    }
}

總結:
非遞歸式的前序和中序很相像,他們的區別在於修改了輸出value的位置。原因在於前序是先輸出根的值,再輸出左節點的值;而中序是先輸出左節點的值,再輸出根的值。

非遞歸式後序遍歷

void PostOrder1(BinaryTreeNode* root){
    if (root==NULL){
        return;
    }
    BinaryTreeNode *node = root;
    stack<BinaryTreeNode*>nodelist;
    BinaryTreeNode *pLastVisted = NULL;
    while(node!=NULL){
        nodelist.push(node);
        node = node->pLeft;
    }//先把所有的左節點放進去 
    while(!nodelist.empty()){
        node = nodelist.top();
        nodelist.pop();//取出棧頂節點 
        if(node->pRight==NULL || node->pRight==pLastVisted){//如果右子樹爲空或者右節點已經訪問過了 
            cout<<node->value;
            pLastVisted=node; 
        }else{
            nodelist.push(node);//先將節點放回去 
            node = node->pRight;//取右節點 
            while(node){
                nodelist.push(node);
                node = node->pLeft;//放入左節點 
            }
        }
    }
}

總結:非遞歸式後序遍歷用到了兩個指針,其中一個要記錄上一次遍歷的那個節點。由於先輸出左右節點的值,再輸出根的值,因此在右節點還沒有遍歷的時候我們先將跟節點放回去,先遍歷右子樹,當右子樹都遍歷完了,再對根節點進行遍歷。


最後附上我的main函數,一個簡單建樹的過程。

int main(){
    //initial
    BinaryTreeNode *node1 = new BinaryTreeNode();
    BinaryTreeNode *node2 = new BinaryTreeNode();
    BinaryTreeNode *node3 = new BinaryTreeNode();
    BinaryTreeNode *node4 = new BinaryTreeNode();
    BinaryTreeNode *node5 = new BinaryTreeNode();
    BinaryTreeNode *node6 = new BinaryTreeNode();
    node1->value = 1;
    node1->pLeft = node2;
    node1->pRight = node3;
    node2->value = 2;
    node2->pLeft = node4;
    node2->pRight = node5;
    node3->value = 3;
    node3->pLeft = node6;
    node3->pRight = NULL;
    node4->value = 4;
    node4->pLeft = NULL;
    node4->pRight = NULL;
    node5->value = 5;
    node5->pLeft = NULL;
    node5->pRight = NULL;
    node6->value = 6;
    node6->pLeft = NULL;
    node6->pRight = NULL;
    PreOrder1(node1);
    cout<<endl;
    InOrder1(node1);
    cout<<endl;
    PostOrder1(node1);
    cout<<endl;
    return 0;
} 

層次遍歷

一般我們實現先序遍歷、中序遍歷和後序遍歷都用的是stack這個數據結構,而在層次遍歷中,我們用queue來實現。
···
vector< vector > levelOrder(TreeNode* root) {
vector< vector > result;
if(root==NULL)
return result;

    queue< TreeNode* > que;
    que.push(root);
    while(!que.empty()){
        vector<int> tmp;
        int size = que.size();
        for(int i=0;i< size;i++){
            TreeNode* node = que.front();
            que.pop();
            tmp.push_back(node->val);
            if(node->left){
                que.push(node->left);
            }
            if(node->right){
                que.push(node->right);
            }
        }
        result.push_back(tmp);
    }
    return result;
}

···

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