根據先序遍歷和中序遍歷建立二叉樹


問題

​ 已知一棵二叉樹的先序遍歷以及中序遍歷,重建二叉樹。二叉樹的每一個節點有三個屬性,左子節點,右子節點,以及節點值。

思路

先序遍歷服從規則“根左右”,所以由此可知,對於一個先序遍歷得到的數組,第一個元素一定是根節點

中序遍歷服從規則”左根右“,所以由此可知,對於一個中序遍歷得到的數組,根節點左邊的元素都屬於根節點的左子樹,而根節點右邊的元素都屬於根節點的右子樹

所以,我們可以先通過先序遍歷的第一個元素確定根節點,然后通過中序遍歷結合根節點,獲得當前根節點的左右子樹,再將子樹看成一棵獨立的樹,繼續使用先序遍歷判斷根節點,中序遍歷判斷子樹的方式,最終建立起整棵樹;

例子

假設有一棵二叉樹,先序遍歷為{1,2,4,7,3,5,6,8},中序遍歷為{4,7,2,1,5,3,8,6},則建樹過程如下:

首先,通過先序遍歷可知樹的根節點為1,則在中序遍歷中,1左邊的元素4,7,2即為根的左子樹的元素,而1右邊的元素5,3,8,6即為根節點的右子樹;

對於左子樹4,7,2來說,在先序遍歷中,這三個點的順序為2,4,7,則2為根節點,而在中序遍歷中,4,7均在2的左邊,則4,7均為以2為根樹的左子樹,且沒有右子樹;

對於4,7這兩個節點來說,先序遍歷中,4節點在7節點之前,所以4為根節點,而7作為子樹,在中序遍歷中,74之后,所以7為右子樹;

對於根節點1的右子樹5,3,8,6來說,在先序遍歷中,3在最前面,所以3為這棵子樹的根節點,而在中序遍歷中,53的左邊,所以屬於左子樹,而8,63的右邊,屬於右子樹;

對於根節點3的右子樹8,6,在先序遍歷中,68之前,所以,6又為根節點,而在中序遍歷中,86的左邊,所以86的左子節點;

至此,二叉樹便重建完成;

代碼

樹的節點

public class TreeNode {
	int val;		//當前節點的值
	TreeNode left;	//左子節點
	TreeNode right;	//右子節點

	TreeNode(int x) {
		val = x;
	}
}

建樹方法

/**
* pre:線序遍歷得到的數組
* in:中序遍歷得到的數組
*/
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
    if(pre.length == 0) {
        return null;
    }

    int root = pre[0];
    TreeNode node = new TreeNode(root);

    //尋找根節點在in中的索引
    int i = 0;
    for( ; i<in.length; ++i) {
        if(in[i] == root) {
            break;
        }
    }

    //建立左子樹
    int[] leftIn = Arrays.copyOfRange(in, 0, i);
    int[] leftPre = Arrays.copyOfRange(pre, 1, i+1);
    node.left = reConstructBinaryTree(leftPre, leftIn);

    //建立右子樹
    int[] rightIn = Arrays.copyOfRange(in, i+1, in.length);
    int[] rightPre = Arrays.copyOfRange(pre, i+1, pre.length);
    node.right = reConstructBinaryTree(rightPre, rightIn);

    return node;
}

建樹代碼(優化)

public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
    return getRootTreeNode(pre, 0, pre.length-1, in, 0, in.length-1);
}

/**
* preL:當前子樹在先序遍歷的數組中的起始下標
* preR:當前子樹在先序遍歷的數組中的結束下標
* inL:當前子樹在中序遍歷的數組中的起始下標
* inR:當前子樹在中序遍歷的數組中的起始下標
*/
public TreeNode getRootTreeNode(int[] pre, int preL, 
                                int preR, int[] in, int inL, int inR) {
    if(preL > preR) {
        return null;
    }

    TreeNode node = new TreeNode(pre[preL]);

    for(int i=inL; i<=inR; ++i) {
        if(in[i] == pre[preL]) {

            node.left = getRootTreeNode(pre, preL+1, preL+i-inL, in, inL, i-1);
            node.right = getRootTreeNode(pre, preL+i-inL+1, preR, in, i+1, inR);
            break;
        }
    }

    return node;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM