1. 程式人生 > >[程式設計師面試題精選100題]4.二叉樹中和為某一值的所有路徑

[程式設計師面試題精選100題]4.二叉樹中和為某一值的所有路徑

【題目】

輸入一個整數和一棵二元樹。從樹的根結點開始往下訪問一直到葉結點所經過的所有結點形成一條路徑。

打印出和與輸入整數相等的所有路徑。

例如輸入整數22和如下二元樹

                                            10
                                           /   \
                                          5     12
                                        /   \   
                                     4     7 

則打印出兩條路徑:10, 12和10, 5, 7。

【分析】

這是百度的一道筆試題,考查對樹這種基本資料結構以及遞迴函式的理解。

當訪問到某一結點時,把該結點新增到路徑上,並累加當前結點的值。

如果當前結點為葉結點並且當前路徑的和剛好等於輸入的整數,則當前的路徑符合要求,我們把它打印出來。

如果當前結點不是葉結點,則繼續訪問它的子結點。當前結點訪問結束後,遞迴函式將自動回到父結點。

因此我們在函式退出之前要在路徑上刪除當前結點並減去當前結點的值,以確保返回父結點時路徑剛好是根結點到父結點的路徑。

我們不難看出儲存路徑的資料結構實際上是一個棧結構,因為路徑要與遞迴呼叫狀態一致,而遞迴呼叫本質就是一個壓棧和出棧的過程。

【程式碼】

/*********************************
*   日期:2013-12-17
*   作者:SJF0115
*   題目: 二叉樹中和為某一值的所有路徑
*   來源:百度
*   分類:經典面試題
**********************************/
#include <iostream>
#include <vector>
using namespace std;

struct TreeNode{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x):val(x),left(NULL),right(NULL){}
};

//輸出路徑
void PrintPath(vector<int> vec){
    int len = vec.size();
    for(int i = 0;i < len;i++){
        if(i != len-1){
            cout<<vec[i]<<"->";
        }
        else{
            cout<<vec[i]<<endl;
        }//if
    }//for
}

//二叉樹中和為某一值的所有路徑
// root 二叉樹
// s 返回的路徑

void FindBinaryTreePath(TreeNode *root,int sum,int& curSum,vector<int>& vec){
    if(root == NULL){
        return;
    }
    TreeNode *cur = root;
    // 入棧
    vec.push_back(cur->val);
    // 當前和
    curSum += cur->val;
    // 是否到達葉子節點
    bool isLeaf = ((cur->left == NULL) && (cur->right == NULL));
    // 找到一條到達葉子節點的路徑
    if(isLeaf && curSum == sum){
        //輸出
        PrintPath(vec);
        return;
    }//if
    // 左子樹
    if(cur->left){
        FindBinaryTreePath(cur->left,sum,curSum,vec);
        // 當我們訪問完該節點,回到父節點
        // 應該從路徑中刪除該節點並且從curSum中減去該節點的值
        curSum -= cur->left->val;
        vec.pop_back();
    }
    // 右子樹
    if(cur->right){
        FindBinaryTreePath(cur->right,sum,curSum,vec);
        // 當我們訪問完該節點,回到父節點
        // 應該從路徑中刪除該節點並且從curSum中減去該節點的值
        curSum -= cur->right->val;
        vec.pop_back();
    }
}

//按先序序列建立二叉樹
int CreateBTree(TreeNode* &T){
    int data;
    //按先序次序輸入二叉樹中結點的值,‘-1’表示空樹
    cin>>data;
    if(data == -1){
        T = NULL;
    }
    else{
        //生成根結點
        T = new TreeNode(data);
        //構造左子樹
        CreateBTree(T->left);
        //構造右子樹
        CreateBTree(T->right);
    }
    return 0;
}

int main(){
    int curSum = 0;
    vector<int> vec;

    TreeNode* root(0);
    CreateBTree(root);

    FindBinaryTreePath(root,22,curSum,vec);
    return 0;
}


測試:

10 5 4 -1 -1 7 -1 -1 12 -1 -1

輸出:

10->5->7

10->12