1. 程式人生 > >劍指Offer-64-二叉搜尋樹的第k個節點

劍指Offer-64-二叉搜尋樹的第k個節點

專案地址:https://github.com/SpecialYy/Sword-Means-Offer

問題

給定一棵二叉搜尋樹,請找出其中的第k小的結點。

解析

二叉搜尋樹是這樣定義的:它允許是棵空樹;根節點的值小於其所有左子樹中的節點,根節點的值大於其所有右子樹中的節點。其左右子樹的所有節點也滿足此約束。比如下圖就是一個二叉樹搜尋樹:

螢幕快照 2018-10-31 23.49.32

很明顯上圖滿足二叉搜尋樹的定義,我們可以發現對於任意一棵子樹,其左孩子<子樹的根節點<右孩子,這不就是中序遍歷的規則。再來看題目要求輸出第k小個節點,我們只需採用中序遍歷的方式找到第k個節點即可。問題就轉換為如何進行中序遍歷二叉樹問題!

思路一

採用遞迴的方式,不斷遞迴深入根節點的左孩子,直到碰到空節點為止,然後回溯輸出當前節點。再以同樣的方式遞迴遍歷其右孩子。在此期間,每訪問一個節點,我們都對k進行減一操作,直到k為0,說明該節點即為第k個節點。

	TreeNode kThNode = null;
    /**
     * 遞迴版中序遍歷
     * @param pRoot
     * @param k
     * @return
     */
    TreeNode KthNode1(TreeNode pRoot, int k) {
        if (pRoot == null) {
            return
null; } int[] count = new int[] {k}; KthNode(pRoot, count); return kThNode; } void KthNode(TreeNode node, int[] count) { if (count[0] != 0 && node != null) { KthNode(node.left, count); if (--count[0] == 0) { kThNode =
node; return; } KthNode(node.right, count); } }

思路二

非遞迴版中序遍歷,如果你理解了遞迴版的寫法,其實改成非遞迴的方式還是挺容易的。因為遞迴的過程其實就是函式不斷的調入,在計算機中每一個函式都是一個棧幀,函式的調入與完成對應入棧與出棧。我們可以利用棧來模擬遞迴遍歷,首先根入棧,然後令根節點的左孩子不斷入棧直到為空,彈出棧頂,令其右孩子入棧,重複以上操作,直到遍歷結束或者訪問第k個節點為止。

	/**
     * 非遞迴版中序遍歷
     * @param pRoot
     * @param k
     * @return
     */
    TreeNode KthNode(TreeNode pRoot, int k) {
        if (pRoot == null) {
            return null;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode p = pRoot;
        while(!stack.isEmpty() || p != null) {
            while(p != null) {
                stack.push(p);
                p = p.left;
            }
            TreeNode node = stack.pop();
            if ((--k) == 0) {
                return node;
            }
            p = node.right;
        }
        return null;
    }

總結

關於二叉樹求某一個節點的問題,都可以嘗試使用先序,中序,後序和層序的方式來解決。