剑指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;
    }

总结

关于二叉树求某一个节点的问题,都可以尝试使用先序,中序,后序和层序的方式来解决。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值