劍指Offer-64-二叉搜尋樹的第k個節點
阿新 • • 發佈:2018-11-10
專案地址:https://github.com/SpecialYy/Sword-Means-Offer
問題
給定一棵二叉搜尋樹,請找出其中的第k小的結點。
解析
二叉搜尋樹是這樣定義的:它允許是棵空樹;根節點的值小於其所有左子樹中的節點,根節點的值大於其所有右子樹中的節點。其左右子樹的所有節點也滿足此約束。比如下圖就是一個二叉樹搜尋樹:
很明顯上圖滿足二叉搜尋樹的定義,我們可以發現對於任意一棵子樹,其左孩子<子樹的根節點<右孩子,這不就是中序遍歷的規則。再來看題目要求輸出第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;
}
總結
關於二叉樹求某一個節點的問題,都可以嘗試使用先序,中序,後序和層序的方式來解決。