劍指offer之打印二叉搜索樹中第k小的結點

題目概述

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

解題思路

一開始我沒有注意到二叉搜索樹這個詞,我仍是覺得是一個普通的二叉樹,因此我就按照個人想法,將二叉樹的節點放入到一個數組中。node

個人解題的思路

因爲一開始我沒有注意到二叉搜索樹這個概念,因此的個人思路是按照普通二叉樹的查找進行的,具體思路以下所示:算法

  1. 首先判斷當前節點是否爲空,k是否小於0.若是爲真,則返回的是null
  2. 新建一個長度爲k個數組,這個數組中將按照Node的val進行排序,排序函數爲moveArr
  3. moveArr函數中定義了將節點按照直接插入排序的思想進行排序。
  4. 而後遞歸的將二叉樹的節點依次放入到數組中,返回數組中的最後一個元素即爲第k小的元素

官方給的題解

當我完成個人算法而且經過的時候,我再一次查看題解時發現,我仍是粗心了,並無發現題目中所給出的隱含的意思。二叉搜索樹是一個很是特別的二叉樹,當一個節點的左子樹和右子樹都存在時,左子樹中的值都小於該節點,右子樹中的全部值都大於該節點。
二叉搜索樹的中序遍歷就是一個升序排序的數組,因此查找第k小的節點,就查找數組中索引爲k-1的節點便可。
可是中序遍歷是找到全部的節點,可是咱們只須要找到第k小的節點便可,因此咱們對算法有了一些改進,使用非遞歸的中序遍歷,找到第k小的節點就跳出循環。數組

具體的思路:函數

  1. 首先判斷當前節點是否爲空,k是否小於0.若是爲真,則返回的是null
  2. 將新建一個Stack棧,用來存放中序遍歷過程當中的節點。
  3. 將執行while循環直到節點爲null與stack爲空時才中止。
  • 在循環過程當中,判斷節點是否爲空,若是不爲空,則將該節點加入到棧中,而且將指針指向節點的左子節點;
  • 若是爲空則將node指向棧拋出的節點上,而後計數器++;判斷是否找到第k個元素,若是找到則返回,若是沒有則將節點指針指向當前節點的右子節點。

代碼的實現

樹節點的函數:this

public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

使用數組存儲的方式

TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot == null || k < 1) return null;
        // 看到這個問題,我首先想到的方法是,將樹放入到一個數組中,而後將數組進行判斷,返現最小的數值
        // 首先新建一個k位大小的數組,而後依次遍歷二叉樹,將數值插入到該數組中
        TreeNode[] arr = new TreeNode[k];
        addTreeNode(pRoot, arr);
        return arr[k-1];
    }
    
    // 遍歷將數節點加入到數組中
    public void addTreeNode(TreeNode node, TreeNode[] arr){
        if(node == null) return;
        moveArr(node, arr);
        if(node.left != null) addTreeNode(node.left, arr);
        if(node.right != null) addTreeNode(node.right, arr);
    }
    
    // 數組移位, 判斷數組要比哪個小
    public void moveArr(TreeNode node, TreeNode[] arr){
        if(node == null) return;
        for(int i=0; i<arr.length; i++){
            if(arr[i] == null){
                arr[i] = node;
                return;
            }else if(node.val < arr[i].val){
                for(int j = arr.length-1; j > i; j--){
                    arr[j] = arr[j-1];
                }
                arr[i] = node;
                return;
            }
        }
    }

使用中序遍歷查找的方法

TreeNode KthNode(TreeNode pRoot, int k){
         // 一開始沒有仔細的看待問題,若是仔細的看問題以及對二叉樹很是熟悉的話,應該第一時間就注意到了 二叉搜索樹 這個詞語
         // ,二叉搜索樹中一個節點的左子樹中的值應該小於該節點,右子樹中的值都應該大於該節點
         if(pRoot == null || k < 1) return null;
         // 二叉樹的中序遍歷就能夠找到該節點的排序,只要找到第k個元素就能夠找到問題中所要找的節點
         // 非遞歸的方法須要使用Stack來存儲父節點
         TreeNode node = pRoot;
         Stack<TreeNode> stack = new Stack<>();
         int count = 0;
         while(node != null || !stack.isEmpty()){
             if(node != null){
                 stack.push(node);
                 node = node.left;
             }else{
                 node = stack.pop();
                 count ++;
                 if(count == k) return node;
                 node = node.right;
             }
         }
         return null;
         
     }
相關文章
相關標籤/搜索