[C++算法] - 二叉樹《21道常見的面試題》

自己動手寫代碼,記錄中間出現的錯誤。

這個網址不錯https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E6%A0%91.md

目錄

中序遍歷!

先序遍歷

後序遍歷

按層遍歷

不分行打印( deque)

分行打印(queue)

Z字遍歷(兩個棧)

Moris神級遍歷

 

二叉樹的層高!

鏡像二叉樹

是否是對稱二叉樹?( pRoot1,  pRoot2)遞歸

 

是否是二叉搜索樹的後序數組?

[98] 驗證二叉搜索樹(BST)

二叉樹的左右邊界打印

[96] 不同的二叉搜索樹

[112] 路徑總和

[113] 路徑總和 II

樹形dp套路

二叉樹節點間的最大距離問題!

派對的最大快樂值  

最大搜索二叉子樹!

是否是平衡二叉樹BST

二叉樹 最近公共祖先

後繼節點(中序遍歷)

二叉樹 累積和爲k的路徑(先序遍歷做)

二叉樹 累積和爲k的最長路徑(先序遍歷做)

重構二叉樹

先序+中序

中序+後序


遞歸遍歷是非常重要的,對於二叉樹的題目來說,雖然單獨讓你寫中序遍歷的時候最好不要用遞歸,但是其他題目中有用到很多。inorder(Node->left,res);一直遞歸到最左邊的null了,返回,此時壓入最左邊節點res.push_back(Node->val);然後看看有沒有右邊的節點,有的話帶進去, inorder(Node->right,res);然後又回到了找最左的過程,以此循環。有一個回溯的過程。

  1. 遞歸遍歷的過程是void函數,注意vector<int>& res,這裏的&符號。
  2. 注意Node->left的時候,要想if(node->left),這裏雖然不用加,但也要有思想的過程。

中序遍歷!

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {     
        vector<int> res;// 全局變量放外面,遞歸
        inorder(root,res);
        return res;
    }
    void inorder(TreeNode * Node,vector<int> &res){
        if (Node==nullptr) return;// basecase
        inorder(Node->left,res);
        res.push_back(Node->val);
        inorder(Node->right,res);
    }
};

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) { 
        TreeNode* cur = root;
        vector<int> res;
        stack<TreeNode *> helpStack;
        while(!helpStack.empty()||cur!=nullptr){//記住這裏的條件
            if(cur!=nullptr){// while裏面if就行
                helpStack.push(cur);
                cur = cur->left;
            }
            else{// 如果cur不爲空!!
                cur = helpStack.top();
                helpStack.pop();
                res.push_back(cur->val);//注意是->val
                cur = cur->right;// 彈出節點的右邊!!
            }
        }
        return res;
    }
};

 


先序遍歷

  1. 先把head放入stack中
  2. 循環while(!stack.empty())
  3. 彈出節點並打印
  4. 將彈出節點的右節點,左節點壓入

cur=stack.top();stack.pop();如果cur->right不爲空stack.push_back(cur->right);如果cur->left不爲空stack.push_back(cur->left);


後序遍歷

利用兩個棧的方式

  1. 先把head在循環外壓入s1,
  2. 當s1不爲空的時候,while(s1不爲空)
  3. 彈出s1到s2中,
  4. 彈出節點的左右一次壓入s1
  5. 最後彈出s2就是

按層遍歷

  • 不分行打印( deque)

#include <deque>
using namespace std;
void PrintFromTopToBottom(BinaryTreeNode* pRoot)
{
    if(pRoot == nullptr)
        return;

    deque<BinaryTreeNode *> dequeTreeNode;

    dequeTreeNode.push_back(pRoot);

    while(dequeTreeNode.size())//!!!!!!
    {
        BinaryTreeNode *pNode = dequeTreeNode.front();
        dequeTreeNode.pop_front();

        printf("%d ", pNode->m_nValue);

        if(pNode->m_pLeft)// !!!
            dequeTreeNode.push_back(pNode->m_pLeft);

        if(pNode->m_pRight)
            dequeTreeNode.push_back(pNode->m_pRight);
    }
}
  • 分行打印(queue)

void Print2(BinaryTreeNode* pRoot) {
	if (pRoot == nullptr)
		return;
	queue<BinaryTreeNode*>q;
	q.push(pRoot);
	int len = 0;
	while (!q.empty()) {//
		len = q.size();// 實時更新len,表示這一層的個數!!
		while (len--) {// 
			BinaryTreeNode *pCur = q.front();
			q.pop();
			cout << pCur->m_nValue<<" ";
			if (pCur->m_pLeft != nullptr) {
				q.push(pCur->m_pLeft);
			}
			if (pCur->m_pRight != nullptr) {
				q.push(pCur->m_pRight);
			}
		}
		cout << endl;	
	}
}

Z字遍歷(兩個棧)

void Print3(BinaryTreeNode* pRoot) {
	if (pRoot == nullptr)
		return;
	stack<BinaryTreeNode*>s1;// 存放奇數層
	stack<BinaryTreeNode*>s2;// 存放偶數層
	s1.push(pRoot);
	int len = 0;
	while (!s1.empty()||!s2.empty())
	{
		while (!s1.empty()){
			len = s1.size();
			while(len--){
				BinaryTreeNode* pCur = s1.top();
				s1.pop();
				cout << pCur->m_nValue<<" ";
				if (pCur->m_pLeft!=nullptr)
					s2.push(pCur->m_pLeft);
				if (pCur->m_pRight != nullptr)
					s2.push(pCur->m_pRight);
			}
		}
		cout << endl;
		while (!s2.empty()) {
			len = s2.size();
			while (len--) {
				BinaryTreeNode* pCur = s2.top();
				s2.pop();
				cout << pCur->m_nValue << " ";
				if (pCur->m_pRight != nullptr)
					s1.push(pCur->m_pRight);
				if (pCur->m_pLeft != nullptr)
					s1.push(pCur->m_pLeft);
			}
		}
		cout << endl;
	}

}

Moris神級遍歷


鏡像二叉樹

將原先的二叉樹變成鏡像二叉樹

利用先序遍歷的方式,遞歸,開始寫basecase(如果是葉子結點了,直接返回)

主體部分:交換該節點的左右節點,如果有左子節點,遞歸交換左子節點的左右,如果有右子節點,遞歸交換右子節點的左右。

void MirrorRecursively(BinaryTreeNode *pNode)
{
    if((pNode == nullptr) || (pNode->m_pLeft == nullptr && pNode->m_pRight))
        return;

    BinaryTreeNode *pTemp = pNode->m_pLeft;
    pNode->m_pLeft = pNode->m_pRight;
    pNode->m_pRight = pTemp;
    
    if(pNode->m_pLeft)
        MirrorRecursively(pNode->m_pLeft);  

    if(pNode->m_pRight)
        MirrorRecursively(pNode->m_pRight); 
}

void MirrorIteratively(BinaryTreeNode* pRoot)
{
    if(pRoot == nullptr)
        return;

    std::stack<BinaryTreeNode*> stackTreeNode;
    stackTreeNode.push(pRoot);

    while(stackTreeNode.size() > 0)
    {
        BinaryTreeNode *pNode = stackTreeNode.top();
        stackTreeNode.pop();   // 根左右,在根處交換左右

        BinaryTreeNode *pTemp = pNode->m_pLeft;
        pNode->m_pLeft = pNode->m_pRight;
        pNode->m_pRight = pTemp;

        if(pNode->m_pLeft)
            stackTreeNode.push(pNode->m_pLeft);

        if(pNode->m_pRight)
            stackTreeNode.push(pNode->m_pRight);
    }
}

是否是對稱二叉樹?( pRoot1,  pRoot2)遞歸

參數是兩個(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)

bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);

bool isSymmetrical(BinaryTreeNode* pRoot)
{
    return isSymmetrical(pRoot, pRoot);
}

bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
    if(pRoot1 == nullptr && pRoot2 == nullptr)//如果都相等
        return true;

    if(pRoot1 == nullptr || pRoot2 == nullptr)// 判斷條件
        return false;

    if(pRoot1->m_nValue != pRoot2->m_nValue)// 判斷條件
        return false;

    return isSymmetrical(pRoot1->m_pLeft, pRoot2->m_pRight)// 遞歸
        && isSymmetrical(pRoot1->m_pRight, pRoot2->m_pLeft);
}

是否是二叉搜索樹的後序數組?

遞歸,參數是(int arr[],length)

後序數組,先找到根節點,然後從開頭開始找比根節點小的數,然後在這之後到最後,如果還有比根節點小的數,則返回false

遞歸的時候看左右是不是,其實還是用先序遍歷的方式~

5 7 6 9 11 10 8

bool VerifySquenceOfBST(int sequence[], int length)
{
    if(sequence == nullptr || length <= 0)
        return false;

    int root = sequence[length - 1]; //更新出根節點value

    // 在二叉搜索樹中左子樹的結點小於根結點
    int i = 0;
    for(; i < length - 1; ++ i)
    {
        if(sequence[i] > root)
            break;
    }

    // 在二叉搜索樹中右子樹的結點大於根結點
    int j = i;
    for(; j < length - 1; ++ j)
    {
        if(sequence[j] < root)
            return false;
    }

    // 判斷左子樹是不是二叉搜索樹
    bool left = true;
    if(i > 0)
        left = VerifySquenceOfBST(sequence, i);// 遞歸,就是數組的範圍在變換

    // 判斷右子樹是不是二叉搜索樹
    bool right = true;
    if(i < length - 1)
        right = VerifySquenceOfBST(sequence + i, length - i - 1);

    return (left && right);//左右是不是
}

 

[98] 驗證二叉搜索樹(BST)

/*
 * 
 * 示例 1:
 * 
 * 輸入:
 * ⁠   2
 * ⁠  / \
 * ⁠ 1   3
 * 輸出: true

 */
class Solution {
    double last = LONG_MIN;//temp
public:
    bool isValidBST(TreeNode* root) {
      if (root == nullptr) {
            return true;
        }
        if (isValidBST(root->left)) {//zuo
            if (last < root->val) {//如果左節點滿足,
                last = root->val;
                return isValidBST(root->right);
            }
        }
        return false;
    }
};

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        // 注意 用long的最大最小值
        return check(root, LONG_MIN, LONG_MAX);
    }
    bool check(TreeNode* root, long min, long max){
        if (root == NULL)
            return true;
        if (root->val <= min || root->val >= max)
            return false;
        return check(root->left, min, root->val) && check(root->right, root->val, max);
    }

}

二叉樹的層高!

用後序遍歷的方式做。

站到頭結點,和左樹右樹,要信息
int getHeight(treeNode * head,int level)
{
    //傳入頭結點,level爲0,返回的level,就是層高
    if (head == nullptr) return level;
    left_height =  getHeight(head->left,level+1);//遞歸的狀態,只應用於本次循環,所以每一對leftright都是一對兒。
    right_height=  getHeight(head->right,level+1);//右樹高度
    return max(left_height,right_height);

}

int getHeight(treeNode * head)
{
    if (head == nullptr) return 0;
    left_height =  getHeight(head->left);//
    right_height=  getHeight(head->right);
    return max(left_height,right_height)+1;

}

// 非遞歸,bfs通過隊列size得到本層的節點數目
int TreeDepth(TreeNode* pRoot)
    {
     queue<TreeNode*> q;
        if(!pRoot) return 0;
        q.push(pRoot);
        int level=0;
        while(!q.empty()){
            int len=q.size();
            level++;
            while(len--){
                TreeNode* tem=q.front();
                q.pop();
                if(tem->left) q.push(tem->left);
                if(tem->right) q.push(tem->right);
            }
        }
        return level;
    } 

 

二叉樹的左右邊界打印

輔助數據:一個二維數組

內部邏輯:中序遍歷,basecase考慮某一節點,if 什麼時候是左邊界,if 什麼時候是右邊界,然後遍歷左右

  • 如果是第一次遍歷到這一層的edgemap[l][0]==nullptr;那麼它就是左邊界,edgemap[l][0]=cur
  • 如果edgemap[l][1],把最後一次遍歷的cur給它就是右邊界,所以不用加判斷,一直edgemap[l][1]=cur,就好,循環到最後就是

凡是和層高有關係的,遞歸函數的形參裏面都有level

  •     setEdgeMap(h->left, l + 1);
  •     setEdgeMap(h->right, l + 1);

 

  • int getHeight(treeNode * head,int level)
  • {
  •     //傳入頭結點,level爲0,返回的level,就是層高
  •     if (head == nullptr) return level;
  •     left_height =  getHeight(head->left,level+1);//遞歸的狀態,只應用於本次循環,所以每一對leftright都是一對兒。
  •     right_height=  getHeight(head->right,level+1);//右樹高度
  •     return max(left_height,right_height);
  • }
#include "stdafx.h"
#include"iostream"
using namespace std;
struct Node {
	Node* left;
	Node* right;
	int data;
	Node(int value):data(value), left(NULL), right(NULL){}
};
Node* T;
Node* edgeMap[100 + 5][2];

void setEdgeMap(Node* h, int l)
{
	// 根左右,中序遍歷,先basecase再判斷,根節點的此處的邏輯,然後左右遍歷
	if (h == NULL) return;
    //左邊界 如果是第一次遇到就令它等於左邊界
	if (edgeMap[l][0] == NULL) 
		edgeMap[l][0] = h;
    //右邊界 是這一層最後一個遍歷到的,所以一直賦予就可以了,到最後就是最右邊界
	edgeMap[l][1] = h;
	setEdgeMap(h->left, l + 1);
	setEdgeMap(h->right, l + 1);
	
}

int main()
{
	Node* node1 = new Node(1);
	Node*node2 = new Node(2);
	Node*node3 = new Node(3);
	Node*node4 = new Node(4);
	Node*node5 = new Node(5);
	Node*node6 = new Node(6);
	Node*node7 = new Node(7);
	Node*node8 = new Node(8);
	Node*node9 = new Node(9);
	Node*node10 = new Node(10);
	Node*node11 = new Node(11);
	Node*node12 = new Node(12);
	Node*node13 = new Node(13);
	Node*node14 = new Node(14);
	Node*node15 = new Node(15);
	Node*node16 = new Node(16);
	node1->left = node2;
	node1->right = node3;
	node2->right = node4;
	node3->left = node5;
	node3->right = node6;
	node4->left = node7;
	node4->right = node8;
	node5->left = node9;
	node5->right = node10;
	node8->right = node11;
	node9->left = node12;
	node11->left = node13;
	node11->right = node14;
	node12->left = node15;
	node12->right = node16;
	setEdgeMap(node1,0);
	for (int i = 0; i < 6; i++)
	{
		cout << edgeMap[i][0]->data<<" ";

	}
	cout << endl;
	for (int i = 0; i < 6; i++)
	{
		cout << edgeMap[i][1]->data << " ";

	}
	cout << endl;

    return 0;
}

[96] 不同的二叉搜索樹

/* 給定 n = 3, 一共有 5 種不同結構的二叉搜索樹:
 * 
 * ⁠  1         3     3      2      1
 * ⁠   \       /     /      / \      \
 * ⁠    3     2     1      1   3      2
 * ⁠   /     /       \                 \
 * ⁠  2     1         2                 3 */
class Solution {// 總結規律,從遍歷的過程。二叉搜索樹的中序遍歷是遞增的。
public:
    int numTrees(int n) {     
        int f[n+1]={0};//注意一定要初始化!!!
        f[0]=1;
        for(int i=1;i<n+1;i++){
            for(int j=1;j<i+1;j++){
                f[i]=f[i]+f[j-1]*f[i-j];//這個就是下面那個的公式
            }
        }
        return f[n];
    }      
};

tricks:  

  1. 不寫累加符號什麼的,直接dp(n)=dp(0)*dp(n-1)+dp(1)*dp(n-2)+dp(2)*dp(n-3)+...+dp(n-1)*dp(0) ,好看。注意dp[0]=1.
  2. 注意dp(n)=dp(0)*dp(n-1)+dp(1)*dp(n-2)+dp(2)*dp(n-3)+...+dp(n-1)*dp(0) 到dp[n] + = dp[j-1]*dp[n-j] 內遍歷,j從1到n。然後到dp[i] + = dp[j-1]*dp[i-j],外遍歷
  3. 注意數組一定要初始化! 動態規劃的題目,有幾個變量就有幾個for,裏面一般就是if什麼的。

[112] 路徑總和

/*
 * 給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。

 * 
 * ⁠             5
 * ⁠            / \
 * ⁠           4   8
 * ⁠          /   / \
 * ⁠         11  13  4
 * ⁠        /  \      \
 * ⁠       7    2      1
 * 
 * 
 * 返回 true, 因爲存在目標和爲 22 的根節點到葉子節點的路徑 5->4->11->2。
 * 
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == nullptr){
            return false;
        }
        if(root->left==nullptr&&root->right==nullptr&&root->val==sum)
            return true;
        if (hasPathSum(root->left, sum-root->val))
            return true;
        if (hasPathSum(root->right, sum-root->val))
            return true;
        return false;
    }
};

[113] 路徑總和 II

 

樹形dp套路

  1. 二叉樹節點間的最大距離問題!

  2. 派對的最大快樂值  

  3. 最大搜索二叉子樹!

  4. 是否是平衡二叉樹BST

  5. 二叉樹 最近公共祖先


後繼節點

是指在中序遍歷中緊隨其後的節點

搜索二叉樹中,刪除一個值什麼的需要後繼節點的函數。

分爲三種情況:

        1.一個節點有右孩子,則在中序遍歷中,該節點的後繼是它的右子樹的最左節點。

        2. 這個節點是它父親的左孩子,則該節點的後繼節點是它的父親

        3. 這個節點是它父親的右孩子,則需要一直向上搜索,直到它們n-1代祖先是它第n代祖先的左孩子,則它的後繼就是第n個祖先。如果一直搜索到根節點,也沒有找到n-1代祖先是它第n代祖先的左孩子,則該節點是整個樹的中序遍歷中的最後一個節點,即它沒有後繼。

protected Node getMinimum(Node node) {
		while (node.left != null) {
			node = node.left;
		}
		return node;
	}



	//找後繼節點
	protected Node getSuccessor(Node node) {
		// if there is right branch, then successor is leftmost node of that
		// subtree
		if (node.right != null) {//如果有右子節點,找右子節點最左邊的
			return getMinimum(node.right);
		} else { // otherwise it is a lowest ancestor whose left child is also
			// ancestor of node//沒有右子節點找父節點
			Node currentNode = node;
			Node parentNode = node.parent;
			while (parentNode != null && currentNode == parentNode.right) {
				// go up until we find parent that currentNode is not in right
				// subtree.
				currentNode = parentNode;
				parentNode = parentNode.parent;
			}
			return parentNode;
		}
	}

二叉樹 累積和爲k的路徑(先序遍歷做

注意這裏的路徑,強調了必須是從根節點到葉節點的路徑纔算。

先序遍歷做(在根節點判斷滿不滿足,然後左右遍歷),遞歸,形參(root,vector,k,cursum)

每次更新的時候,

  1. 根節點處:需要更新cursum和vector,判斷cursum是不是等於k && 當前的節點是不是葉子節點,滿足條件遍歷vector,打印。
  2. 遍歷左右子節點:如果左子節點不爲空,遍歷遞歸左邊,如果右子節點不爲空,遍歷遞歸右邊。
  3. 在末尾,返回父函數的時候,吧vector和cursum減去當前的值。
void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int& currentSum);

void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{
    if(pRoot == nullptr)
        return;

    std::vector<int> path;
    int currentSum = 0;
    FindPath(pRoot, expectedSum, path, currentSum);
}

void FindPath
(
    BinaryTreeNode*   pRoot,        
    int               expectedSum,  
    std::vector<int>& path,         
    int&              currentSum
)
{   //更新參數
    currentSum += pRoot->m_nValue;
    path.push_back(pRoot->m_nValue);

    // 如果是葉結點,並且路徑上結點的和等於輸入的值
    // 打印出這條路徑
    bool isLeaf = pRoot->m_pLeft == nullptr && pRoot->m_pRight == nullptr;
    if(currentSum == expectedSum && isLeaf)
    {
        printf("A path is found: ");
        std::vector<int>::iterator iter = path.begin();
        for(; iter != path.end(); ++ iter)
            printf("%d\t", *iter);
        
        printf("\n");
    }

    // 如果有相應的節點,則遍歷它的子結點
    if(pRoot->m_pLeft != nullptr)
        FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);
    if(pRoot->m_pRight != nullptr)
        FindPath(pRoot->m_pRight, expectedSum, path, currentSum);

    // 在返回到父結點之前,在路徑上刪除當前結點,
    // 並在currentSum中減去當前結點的值
    currentSum -= pRoot->m_nValue;
    path.pop_back();
} 

二叉樹 累積和爲k的最長路徑

這道題需要數組裏累積和爲k的最長路徑作爲基礎,同樣是利用map,來做,不同的是,這裏開始時map[0]=0,表示什麼都不加的時候0層。先序遍歷做,和上一題差不多,在根節點處判斷,然後遍歷左右子節點,返回父節點的時候需要特別注意一下。

需要的參數 root,cursum,k,map,level,maxlen

int getMaxlen(BinaryTreeNode *root, int k) {
	if (root == nullptr)return 0;
	map<int, int>m;
	m[0] = 0;
	getMaxlen(root, k, 0, 1, 0, m);// 當前第一層
}

int getMaxlen(BinaryTreeNode *root, int k, int cursum, int level, int maxlen, map<int, int>m) {
	cursum += root->m_nValue;
	if (!m.count(cursum)) {
		m[cursum] = level;
	}
	if (m.count(cursum - k)) {
		maxlen = max(maxlen, level - m[cursum - k]);
	}
	maxlen = getMaxlen(root->m_pLeft, k, cursum, level + 1, maxlen, m);
	maxlen = getMaxlen(root->m_pRight, k, cursum, level + 1, maxlen, m);
	if ( m[cursum]==level ) {
		m.erase(cursum);
	}
	return maxlen;
}

重構二叉樹

  1. 先序+中序

  2. 中序+後序

其他的情況我就不寫了,值得說明的是先序+後序重構二叉樹有些是重構不出來的。而上面的兩個,基本思路一致,我就只說明第一個了。注意這裏的二叉樹都不含重複的數字!

先序 根左右   1 2 4 7 3 5 6 8

中序 左根右   4 7 2 1 5 3 8 6

首先從先序中找到根,然後在中序中找到根的位置,以此判斷左子樹和右子樹。不斷遞歸。每次遞歸返回的都是當前狀態的根節點。

函數的參數有(先序開始,先序的結束,中序的開始,中序的結束)也是那種常見的數組的開頭和結尾,不斷縮短的形式

作用是:返回當前的根節點,並利用確定的左右子樹的範圍,構建左右子樹(利用遞歸函數)

// 需要先聲明
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
{
    if(preorder == nullptr || inorder == nullptr || length <= 0)
        return nullptr;

    return ConstructCore(preorder, preorder + length - 1,
        inorder, inorder + length - 1);
}

BinaryTreeNode* ConstructCore//注意這裏的參數,也是那種常見的數組的開頭和結尾,不斷縮短的形式
(
    int* startPreorder, int* endPreorder, 
    int* startInorder, int* endInorder
)
{
    // 前序遍歷序列的第一個數字是根結點的值
    int rootValue = startPreorder[0];
    BinaryTreeNode* root = new BinaryTreeNode();// 注意這裏構建的形式
    root->m_nValue = rootValue;// 初始化
    root->m_pLeft = root->m_pRight = nullptr;
    // basecase 先序和中序數組都是剩下一個值,這個值必須還是相等的
    if(startPreorder == endPreorder)
    {   
        if(startInorder == endInorder && *startPreorder == *startInorder)
            return root;
        else
            throw std::exception("Invalid input.");
    }

    // 在中序遍歷中找到根結點的值
    int* rootInorder = startInorder;
    while(rootInorder <= endInorder && *rootInorder != rootValue)
        ++ rootInorder;

    if(rootInorder == endInorder && *rootInorder != rootValue)
        throw std::exception("Invalid input.");

    int leftLength = rootInorder - startInorder;
    int* leftPreorderEnd = startPreorder + leftLength;
    if(leftLength > 0)// 如果有左子樹
    {
        // 構建左子樹,注意這裏函數返回的是左子樹的根節點
        root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, 
            startInorder, rootInorder - 1);
    }// 如果有右子樹
    if(leftLength < endPreorder - startPreorder)
    {
        // 構建右子樹
        root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder,
            rootInorder + 1, endInorder);
    }

    return root;
}

 

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