劍指offer之二叉樹總結

會用遞歸了二叉樹的問題就會一大半了...

一.用遞歸求解

對於要利用二叉樹的規律的題都可以利用它的左節點也是其左子樹的根節點的特性來遞歸求解。可以說那種參數有根節點的題一般都可以用遞歸來解決,來看看《劍指offer》中可用遞歸解決的題

1.根據前序遍歷的性質,第一個元素必然就是root,那麼下面的工作就是如何確定root的左右子樹的範圍。根據中序遍歷的性質,root元素前面都是root的左子樹,後面都是root的右子樹。那麼我們只要找到中序遍歷中root的位置,就可以確定好左右子樹的範圍

struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
    int inlen=in.size();
    if(inlen==0)
        return NULL;
    vector<int> left_pre,right_pre,left_in,right_in;
    TreeNode* head=new TreeNode(pre[0]);
    int gen=0;
    for(int i=0;i<inlen;i++)
    {
        if (in[i]==pre[0])
        {
            gen=i;

            break;
        }
    }
    for(int i=0;i<gen;i++)
    {
        left_in.push_back(in[i]);

        left_pre.push_back(pre[i+1]);
    }
    for(int i=gen+1;i<inlen;i++)
    {
        right_in.push_back(in[i]);
        right_pre.push_back(pre[i]);
    }
    head->left=reConstructBinaryTree(left_pre,left_in);
    head->right=reConstructBinaryTree(right_pre,right_in);
    return head;

}

2.輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

bool isSubtree(TreeNode* pRootA, TreeNode* pRootB) {
    if (pRootB == NULL) return true;
    if (pRootA == NULL) return false;
    if (pRootB->val == pRootA->val) {
        return isSubtree(pRootA->left, pRootB->left)
               && isSubtree(pRootA->right, pRootB->right);
    } else return false;
}
bool HasSubtree(TreeNode* pRootA, TreeNode* pRootB)
{
    if (pRootA == NULL || pRootB == NULL) return false;
    return isSubtree(pRootA, pRootB) ||
           HasSubtree(pRootA->left, pRootB) ||
           HasSubtree(pRootA->right, pRootB);
}

首先對於A,B當前節點,如果相等那麼就接着判斷他們的左子樹上的節點是否相等以及右子樹上的節點是否相等

3.操作給定的二叉樹,將其變換爲源二叉樹的鏡像

void Mirror(TreeNode *pRoot) {
    if(pRoot==NULL){
        return;
    }
    TreeNode *tmp = pRoot->left;
    pRoot->left = pRoot->right;
    pRoot->right = tmp;
    Mirror(pRoot->left);
    Mirror(pRoot->right);
}

4.輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。

bool judge(vector<int>& a){
    int size = a.size();
    if(0==size)return false;

    int i = 0;
    while(--size)
    {
        while(a[i++]<a[size]);
        while(a[i++]>a[size]);
        if(i<size)return false;
        i=0;
    }
    return true;

}

後序遍歷出的數組元素特點是對於每個點的前面所有元素,都是一部分小於它然後又是大於它

5.輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)

class Solution {
public:
    vector<vector<int>> res;
    int ex;
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        this->ex = expectNumber;
        if(root == NULL)
            return res;
        TreeNode* temp = root;
        vector<int>s;
        int sum = 0;
        BSD(root,s,sum);
        return this->res;
    }
    void BSD(TreeNode* root,vector<int>s,int sum){
        sum += root->val;
        s.push_back(root->val);
        if(root->left == NULL && root->right == NULL){

            if(sum == ex)
                res.push_back(s);
            sum = 0;
            while(!s.empty()) s.pop_back();
            return;
        }

        if(root->left != NULL) BSD(root->left,s,sum);
        if(root->right != NULL) BSD(root->right,s,sum);
    }
};

6.輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if( pRootOfTree == NULL)
            return NULL;
        TreeNode* root = pRootOfTree;
        TreeNode* p = pRootOfTree;
        TreeNode* pre = pRootOfTree;
        stack<TreeNode*> ss;
        bool isroot = true;
        while(!ss.empty() || p != NULL){
            while(p != NULL){
                ss.push(p);
                p = p->left;
            }
            p = ss.top();
            ss.pop();
            if(isroot){
                root = p;
                pre = root;
                isroot = false;
            }else{
                pre->right = p;
                p->left = pre;
                pre =  p;
            }
            p = p->right;
        }
        return root;
    }
};

7.輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。

int TreeDepth(TreeNode* pRoot)
{
    if(pRoot == NULL)
        return 0;
    int height = max(TreeDepth(pRoot->left),TreeDepth(pRoot->right))+1;
    return height;
}

8.輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot == NULL)
            return true;
        return getheight(pRoot) != -1;
    }
    int getheight(TreeNode* node){
        if(node == NULL)
            return 0;
        int left = getheight(node->left);
        if(left == -1)
            return -1;
        int right = getheight(node->right);
        if(right == -1)
            return -1;
        int cnt = abs(left-right) > 1?-1:1;
        return cnt + max(left,right);

    }
};

上面題思路其實都一樣,掌握了遞歸對這些題還是很簡單

還有是對某一節點的分析

9.給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode == NULL)
            return NULL;
        if(pNode->right == NULL){
            while(pNode->next != NULL){
                if(pNode->next->left == pNode)
                    return pNode->next;
                pNode = pNode->next;
            }
            return NULL;
        }

        else{
            TreeLinkNode* temp = pNode->right;
            while(temp->left != NULL){
                temp = temp->left;
            }
            return temp;
        }
    }
};

主要是分幾種情況

右節點爲空:當前節點是不是其父節點的左節點

(1)若是則後繼節點爲其父節點

(2)若不是就一直往上遍歷直至找到爲左節點的點

右節點不爲空:再看右節點有無左節點

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