1. 程式人生 > 其它 >C++二叉樹

C++二叉樹

技術標籤:C++雜項

兩種特殊二叉樹
1.滿二叉樹:除葉子節點外的所有分支節點都含有2個非空子節點的二叉樹
2.完全二叉樹:除了最後一層,其餘層都是“滿”的,這樣的二叉樹是完全二叉樹

二叉樹定理
1)任意二叉樹度數為2節點的個數等於葉節點個數減1
當只有1個節點時,度為0。每派生出1度,就會多出1個節點。派生出的度和派生出的節點數一定相等。那麼就得出了總度數和節點總數的關係:
節點總數 = 總度數 + 1
設度數為2的節點數為X2,度數為1的節點數為X1,度數為0的節點數為X0。可以得出如下關係式:
X2 + X1 + X0 = 2X2 + X1 + 1,推出 X2 = X0 - 1
因此,度數為2的節點個數等於葉節點數減1

2)滿二叉樹定理:非空滿二叉樹的葉節點數等於其分支節點數加1
如果已知前一個結論,那麼這個定理顯然成立。下面分析如果不知道前一個結論,怎麼證明
對於只有1個節點的樹,該定理成立。從這開始思考,每產生1個分支節點(度數為2)。葉子節點數也會加1。因為要產生一個分支節點,那麼這個新的分支節點必然是原來的葉子節點,而新的分支節點又生成了2個新的葉子節點。因此葉子節點的總數先是減1然後加2,因此總數加1。因此,產生n個分支節點時,也產生了n個葉子節點,由於最初只有1個葉子節點,所以該定理成立

3)一顆非空二叉樹空子樹的數目等於其節點數目加1
考慮只有1個根節點的二叉樹:它有2個空子樹,1個節點,因此結論成立。從這裡開始考慮,每產生1個節點。空子樹便會先減1然後加2。就和上面結論中每多出1個分支節點,葉子節點的變化一樣。因此在原來結論的基礎上,由於空子樹和節點等量增長。所以結論成立

前中後序遍歷

3.前序遍歷:根->左->右

4.中序遍歷:左->根->右

5.後序遍歷:左->右->根

假設樹節點的定義如下:

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

遞迴版
//前序遍歷

void preorderTraversalRecursion(TreeNode *node)
{
    if(!node) return;
    cout <<
node->val << " ";//操作當前節點 preorderTraversalRecursion(node->left); preorderTraversalRecursion(node->right); }

//中序遍歷

void inorderTraversalRecursion(TreeNode *node)
{
    if(!node) return;
    inorderTraversalRecursion(node->left);
    cout << node->val << " ";//操作當前節點
    inorderTraversalRecursion(node->right);
}

//後序遍歷

void postorderTraversalRecursion(TreeNode *node)
{
    if(!node) return;
    postorderTraversalRecursion(node->left);
    postorderTraversalRecursion(node->right);
    cout << node->val << " ";//操作當前節點
}

迭代版
需要使用一個棧作為輔助空間

//前序遍歷
void preorderTraversalIteration(TreeNode *root)
{
    stack<TreeNode*> st;
    if(root)
        st.push(root);

    while(!st.empty()){
        TreeNode *nd = st.top();
        st.pop();

        cout << nd->val << " ";//操作當前節點

        if(nd->right)
            st.push(nd->right);
        if(nd->left)
            st.push(nd->left);
    }
}
//中序遍歷:
void inorderTraversalIteration(TreeNode *root)
{
    stack<TreeNode*> st;

    TreeNode *curr = root;

    while(curr || !st.empty()){
        if(curr){
            st.push(curr);
            curr = curr->left;
        }
        else{
            curr = st.top();
            st.pop();

            cout << curr->val << " ";//操作當前節點

            curr = curr->right;
        }
    }
}
//後序遍歷
void postorderTraversalIteration(TreeNode *root)
{
    stack<TreeNode*> st;
    TreeNode *pre;

    if(root)
        st.push(root);

    while(!st.empty()){
        TreeNode *nd = st.top();
        /*
         * 出棧條件:
         * 對於葉子節點:直接彈出
         * 對於非葉子節點:如果已經遍歷過其左子節點或右子節點,則彈出
         */
        if((!nd->left && !nd->right) || (pre && (nd->left == pre || nd->right == pre))){
            st.pop();
            cout << nd->val <<" ";//操作當前節點
            pre = nd;
        }
        else{//說明是一個非葉子節點,並且還未訪問其左右孩子
            if(nd->right)
                st.push(nd->right);
            if(nd->left)
                st.push(nd->left);
        }
    }
}

對於後序遍歷,由於其訪問序列為:左->右->根。因此還有一種方法,可以按類似前序遍歷的方式:根->右->左,然後對得到的結果反序