一文高效图解二叉树面试题

点击蓝色“码出高效面试的程序媛”关注我,

了解更多技术流行面试题

二叉树,搜索二叉树,是算法面试的必面题。聊聊面试点:

一、树 & 二叉树

树的组成为节点和边,节点用来储存元素。节点组成为根节点、父节点和子节点。

如图:树深 length 为 4;根节点的值为 5 ;父子节点关系:值为 8 和 值为 3 的节点

理解了树,那什么是二叉树?

二叉树 (Binary Tree),二叉是分叉的意思,就是用边区分。节点最多有两个子节点,分别为左子节点和右子节点。连接节点的就是边,所以节点最多会有三条边。二叉树的场景很多,比如用来表示算术表达式等等。

如图:值为 1 或者 8 的节点是左节点;值为 2 或 3 的节点是右节点;

二、二叉搜索树 BST

上面理解了二叉树,那么搜索二叉树就好理解了。搜索二叉树为了搜索而设计,要求也是将无序存储变成有序。即每个节点的值要比左子树的值大,比右子树的值小。

如图:

Java 实现代码如下:

 
  1. public class BinarySearchTree {

  2.    /**

  3.     * 根节点

  4.     */

  5.    public static TreeNode root;

  6.  

  7.    public BinarySearchTree() {

  8.        this.root = null;

  9.    }

  10.  

  11.    /**

  12.     * 查找

  13.     */

  14.    public TreeNode search (int key) {

  15.        TreeNode current = root;

  16.        while (current != null

  17.                && key != current.value) {

  18.            if (key < current.value )

  19.                current = current.left;

  20.            else

  21.                current = current.right;

  22.        }

  23.        return current;

  24.    }

  25.  

  26.    /**

  27.     * 插入

  28.     */

  29.    public TreeNode insert (int key) {

  30.        // 新增节点

  31.        TreeNode newNode = new TreeNode(key);

  32.        // 当前节点

  33.        TreeNode current = root;

  34.        // 上个节点

  35.        TreeNode parent  = null;

  36.        // 如果根节点为空

  37.        if (current == null) {

  38.            root = newNode;

  39.            return newNode;

  40.        }

  41.        while (true) {

  42.            parent = current;

  43.            if (key < current.value) {

  44.                current = current.left;

  45.                if (current == null) {

  46.                    parent.left = newNode;

  47.                    return newNode;

  48.                }

  49.            } else {

  50.                current = current.right;

  51.                if (current == null) {

  52.                    parent.right = newNode;

  53.                    return newNode;

  54.                }

  55.            }

  56.        }

  57.    }

  58.  

  59.    /**

  60.     * 删除节点

  61.     */

  62.    public TreeNode delete (int key) {

  63.        TreeNode parent  = root;

  64.        TreeNode current = root;

  65.        boolean isLeftChild = false;

  66.        // 找到删除节点 及 是否在左子树

  67.        while (current.value != key) {

  68.            parent = current;

  69.            if (current.value > key) {

  70.                isLeftChild = true;

  71.                current = current.left;

  72.            } else {

  73.                isLeftChild = false;

  74.                current = current.right;

  75.            }

  76.  

  77.            if (current == null) {

  78.                return current;

  79.            }

  80.        }

  81.  

  82.        // 如果删除节点左节点为空 , 右节点也为空

  83.        if (current.left == null && current.right == null) {

  84.            if (current == root) {

  85.                root = null;

  86.            }

  87.            // 在左子树

  88.            if (isLeftChild == true) {

  89.                parent.left = null;

  90.            } else {

  91.                parent.right = null;

  92.            }

  93.        }

  94.        // 如果删除节点只有一个子节点 右节点 或者 左节点

  95.        else if (current.right == null) {

  96.            if (current == root) {

  97.                root = current.left;

  98.            } else if (isLeftChild) {

  99.                parent.left = current.left;

  100.            } else {

  101.                parent.right = current.left;

  102.            }

  103.  

  104.        }

  105.        else if (current.left == null) {

  106.            if (current == root) {

  107.                root = current.right;

  108.            } else if (isLeftChild) {

  109.                parent.left = current.right;

  110.            } else {

  111.                parent.right = current.right;

  112.            }

  113.        }

  114.        // 如果删除节点左右子节点都不为空

  115.        else if (current.left != null && current.right != null) {

  116.            // 找到删除节点的后继者

  117.            TreeNode successor = getDeleteSuccessor(current);

  118.            if (current == root) {

  119.                root = successor;

  120.            } else if (isLeftChild) {

  121.                parent.left = successor;

  122.            } else {

  123.                parent.right = successor;

  124.            }

  125.            successor.left = current.left;

  126.        }

  127.        return current;

  128.    }

  129.  

  130.    /**

  131.     * 获取删除节点的后继者

  132.     *      删除节点的后继者是在其右节点树种最小的节点

  133.     */

  134.    public TreeNode getDeleteSuccessor(TreeNode deleteNode) {

  135.        // 后继者

  136.        TreeNode successor = null;

  137.        TreeNode successorParent = null;

  138.        TreeNode current = deleteNode.right;

  139.  

  140.        while (current != null) {

  141.            successorParent = successor;

  142.            successor = current;

  143.            current = current.left;

  144.        }

  145.  

  146.        // 检查后继者(不可能有左节点树)是否有右节点树

  147.        // 如果它有右节点树,则替换后继者位置,加到后继者父亲节点的左节点.

  148.        if (successor != deleteNode.right) {

  149.            successorParent.left = successor.right;

  150.            successor.right = deleteNode.right;

  151.        }

  152.  

  153.        return successor;

  154.    }

  155.  

  156.    public void toString(TreeNode root) {

  157.        if (root != null) {

  158.            toString(root.left);

  159.            System.out.print("value = " + root.value + " -> ");

  160.            toString(root.right);

  161.        }

  162.    }

  163. }

  164.  

  165. /**

  166. * 节点

  167. */

  168. class TreeNode {

  169.  

  170.    /**

  171.     * 节点值

  172.     */

  173.    int value;

  174.  

  175.    /**

  176.     * 左节点

  177.     */

  178.    TreeNode left;

  179.  

  180.    /**

  181.     * 右节点

  182.     */

  183.    TreeNode right;

  184.  

  185.    public TreeNode(int value) {

  186.        this.value = value;

  187.        left  = null;

  188.        right = null;

  189.    }

  190. }

面试点一:理解 TreeNode 数据结构

节点数据结构,即节点、左节点和右节点。如图

面试点二:如何确定二叉树的最大深度或者最小深度

答案:简单的递归实现即可,代码如下:

 
  1. int maxDeath(TreeNode node){

  2.    if(node==null){

  3.        return 0;

  4.    }

  5.    int left = maxDeath(node.left);

  6.    int right = maxDeath(node.right);

  7.    return Math.max(left,right) + 1;

  8. }

  9.  

  10.    int getMinDepth(TreeNode root){

  11.        if(root == null){

  12.            return 0;

  13.        }

  14.        return getMin(root);

  15.    }

  16.    int getMin(TreeNode root){

  17.        if(root == null){

  18.            return Integer.MAX_VALUE;

  19.        }

  20.        if(root.left == null&&root.right == null){

  21.            return 1;

  22.        }

  23.        return Math.min(getMin(root.left),getMin(root.right)) + 1;

  24.    }

面试点三:如何确定二叉树是否是平衡二叉树

答案:简单的递归实现即可,代码如下:

    boolean isBalanced(TreeNode node){        return maxDeath2(node)!=-1;    }    int maxDeath2(TreeNode node){        if(node == null){            return 0;        }        int left = maxDeath2(node.left);        int right = maxDeath2(node.right);        if(left==-1||right==-1||Math.abs(left-right)>1){            return -1;        }        return Math.max(left, right) + 1;    }

前面面试点是 二叉树 的,后面面试点是 搜索二叉树 的。先运行搜搜二叉树代码:

 
  1. public class BinarySearchTreeTest {

  2.  

  3.    public static void main(String[] args) {

  4.        BinarySearchTree b = new BinarySearchTree();

  5.        b.insert(3);b.insert(8);b.insert(1);b.insert(4);b.insert(6);

  6.        b.insert(2);b.insert(10);b.insert(9);b.insert(20);b.insert(25);

  7.  

  8.        // 打印二叉树

  9.        b.toString(b.root);

  10.        System.out.println();

  11.  

  12.        // 是否存在节点值10

  13.        TreeNode node01 = b.search(10);

  14.        System.out.println("是否存在节点值为10 => " + node01.value);

  15.        // 是否存在节点值11

  16.        TreeNode node02 = b.search(11);

  17.        System.out.println("是否存在节点值为11 => " + node02);

  18.  

  19.        // 删除节点8

  20.        TreeNode node03 = b.delete(8);

  21.        System.out.println("删除节点8 => " + node03.value);

  22.        b.toString(b.root);

  23.  

  24.  

  25.    }

  26. }

结果如下:

value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 8 -> value = 9 -> value = 10 -> value = 20 -> value = 25 -> 是否存在节点值为10 => 10是否存在节点值为11 => null删除节点8 => 8value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->

面试点四:搜索二叉树如何实现插入

插入,还是比较容易理解的。就按照要求,插入到指定的位置。如果插入到叉搜索树的中间节点,那么会引起节点的动态变化。如图插入的逻辑:

  1. 值为 2 的节点开始判断

  2. 如果为空,则插入该节点

  3. 循环下面节点:

    1. 节点当前值大于,继续循环左节点

    2. 节点当前值小于,继续循环右节点

面试点五:搜索二叉树如何实现查找

算法复杂度 : O(lgN)。如图搜索及查找逻辑:

  1. 值为 2 的节点开始判断

    1. 节点当前值大于,继续循环左节点

    2. 节点当前值小于,继续循环右节点

  2. 如果值相等,搜索到对应的值,并返回

  3. 如果循环完毕没有,则返回未找到

面试点五:搜索二叉树如何实现删除

比较复杂了。相比新增、搜搜,删除需要将树重置。逻辑为:删除的节点后,其替代的节点为,其右节点树中值最小对应的节点。如图:

结果为:

三、小结

就像码出高效面试的程序媛偶尔吃一碗“老坛酸菜牛肉面”一样的味道,品味一个算法,比如 BST 的时候,总是那种说不出的味道。

面试必备小结:

  • 树,二叉树的概念

  • BST 算法

 

如以上文章或链接对你有帮助的话

可以点击页面右上角边按钮哦,让更多的人阅读这篇文章

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值