/**
* 給定一棵二叉搜索樹,請找出其中的第k小的結點。
* 例如, (5,3,7,2,4,6,8)中,
* 按結點數值大小順序第三小結點的值爲4。
* 這是層序遍歷:
* 5
* 3 7
* 2 4 6 8
思路:
二叉搜索樹的中序遍歷(左--中--右)就是按照從小到大進行排好序的結果,因此若是你想輸出第k小的節點就是找到從左到右的第k個數就ok了!
因此這個問題能夠轉化爲求二叉搜索樹的中序遍歷的方法!
遞歸版:
public TreeNode kthNode2(TreeNode pRoot,int k) { if(pRoot==null||k==0) return null; inorder(pRoot,k); return root; } private void inorder(TreeNode pRoot, int k) { if(pRoot==null) return; inorder(pRoot.left,k); //返回完了以後就對應着倒數第一個節點! cnt++; if(cnt==k) root = pRoot; inorder(pRoot.right,k); }
其實思路很簡單,可是須要人爲的去在腦子裏過一遍,由於是二叉搜索樹,因此最最最左邊的節點,必定是最小的,所以咱們須要直接走到整棵樹的最左邊的節點,也就是2!用遞歸的方法如何實現呢?函數
inorder(pRoot.left,k); + (if(pRoot==null) return;) 兩個神器搭配就能夠直接走到整棵樹的最左邊的節點!而後接下來的任務就有意思了,進到最左邊的節點以後,它必定是最小的,因此咱們讓全局變量cnt++;也就是說它表明了倒數第一小的節點!以後是一個if判斷,if(cnt==k),root=pRoot;若是相等了表明當前節點就是你要找的節點,直接給TreeNode root賦值就能夠結束,不然的話,繼續進到它的右節點進行尋找!爲何這裏要進右節點呢?spa
考慮第一次返回,說明2節點的左子樹確定爲null,那麼根據中序遍歷 左--->中---->右的原則,你找完了中間節點,必須去到它的右子樹裏看看是否存在右子樹!若是右子樹存在,那麼繼續一路飆到最左邊,而後count++!這才表明了倒數第二個節點的存在!當你的右子樹找完以後,天然函數會返回,那麼它返回的必定是上一層的中間節點3!此時依然要執行3這個節點的右節點!由於你返回上去以後,它必定是上一層的樹的中間節點,而你剛剛進入下以層找的剛好是它的左子樹!因此要繼續找3的右子樹!code
這就是爲何每次count++;以後要找右子樹再進入遞歸的緣由!由於你在遞歸進左子樹的過程當中你實際上進入的是(1 子樹結構的左節點,2 「根」結構的中間節點)blog
因此,你一旦返回就證實着你如今位於高層次樹的中間節點上,接下來等着你處理的必定是右子樹!!!遞歸
以上是我對遞歸法中序遍歷二叉搜索樹的一些理解!class
1 if(pRoot==null|| k==0) 2 return null; 3 int count=0; 4 Stack<TreeNode> stack = new Stack<>(); 5 while(pRoot!=null || !stack.isEmpty()) 6 { 7 8 while(pRoot!=null) 9 { 10 stack.push(pRoot); 11 pRoot = pRoot.left; 12 } 13 pRoot = stack.pop();//倒數第一小的節點出來了! 14 count++; 15 if(count==k) 16 return pRoot; 17 pRoot = pRoot.right; 18 } 19 return null;
如今我以爲迭代的實現其實就是把原來遞歸隱式使用計算機棧的規則給顯式的表示出來!新建一個棧,while(pRoot!=null || !stack.isEmpty())當pRoot沒走到最後或者棧裏面還有元素的時候咱們就在這個循環裏面繼續進行繼續判斷若是是pRoot!=null那麼二話不說直接壓棧到最左邊的節點同樣的操做!從棧裏面彈出一個節點,此時的節點就是最左邊的最小值,而後count++;後面的代碼和遞歸版基本一致!判斷等不等於k,而後繼續!最關鍵的是最後的一行代碼,pRoot = pRoot.right;咱們仍舊須要進入到它的右子樹裏面重複執行,此時咱們會看這個條件!while(pRoot!=null||!stack.isEmpty())它其實就是表明的兩種狀況 : 1 右子樹存在,那麼繼續壓棧處理走到最左邊慢慢往上升 2 右子樹不存在程序返回,那麼此時棧就必須存在樹節點,而此時的樹節點就恰好是上層的中間節點了!因此一個很是重要的思想是:節點在子樹裏面充當的是左節點!一旦它上升到上一層樹的級別,那麼在這個結構裏面它就是中間節點,因此必須往右子樹裏繼續執行!