点击“码出高效面试的程序媛”关注我,
了解更多技术流行面试题
二叉树,搜索二叉树,是算法面试的必面题。聊聊面试点:
一、树 & 二叉树 树的组成为节点和边,节点用来储存元素。节点组成为根节点、父节点和子节点。
如图:树深 length 为 4;根节点的值为 5 ;父子节点关系:值为 8 和 值为 3 的节点
理解了树,那什么是二叉树?
二叉树 (Binary Tree),二叉是分叉的意思,就是用边区分。节点最多有两个子节点,分别为左子节点和右子节点。连接节点的就是边,所以节点最多会有三条边。二叉树的场景很多,比如用来表示算术表达式等等。
如图:值为 1 或者 8 的节点是左节点;值为 2 或 3 的节点是右节点;
二、二叉搜索树 BST 上面理解了二叉树,那么搜索二叉树就好理解了。搜索二叉树为了搜索而设计,要求也是将无序存储变成有序。即每个节点的值要比左子树的值大,比右子树的值小。
如图:
Java 实现代码如下:
public
class
BinarySearchTree
{ /**
* 根节点
*/
复制代码
public static TreeNode root ; public BinarySearchTree () {
this . root
null ; }
/** * 查找 */ public TreeNode search ( int key ) {
TreeNode current
root ;
while
( current !=
null
&& key != current . value )
{
if
( key < current . value )
current
复制代码
= current . left ;
else
current
复制代码
= current . right ;
}
return current ;
}
/**
* 插入
*/
复制代码
public
TreeNode insert ( int key )
{
// 新增节点
TreeNode newNode
new
TreeNode ( key );
// 当前节点
TreeNode current
root ;
// 上个节点
TreeNode parent
null ;
// 如果根节点为空
if
( current
null )
{
root
复制代码
= newNode ;
return newNode ;
}
while
( true )
{
parent
复制代码
= current ;
if
( key < current . value )
{
current
复制代码
= current . left ;
if
( current
null )
{
parent
复制代码
. left
newNode ;
return newNode ;
}
}
else
{
current
复制代码
= current . right ;
if
( current
null )
{
parent
复制代码
. right
newNode ;
return newNode ;
}
}
}
}
/**
* 删除节点
*/
复制代码
public
TreeNode
delete
( int key )
{
TreeNode parent
root ;
TreeNode current
root ;
boolean isLeftChild
false ;
// 找到删除节点 及 是否在左子树
while
( current . value != key )
{
parent
复制代码
= current ;
if
( current . value
key )
{
isLeftChild
复制代码
=
true ;
current
复制代码
= current . left ;
}
else
{
isLeftChild
复制代码
=
false ;
current
复制代码
= current . right ;
}
if
( current
null )
{
return current ;
}
}
// 如果删除节点左节点为空 , 右节点也为空
if
( current . left
null
&& current . right
null )
{
if
( current
root )
{
root
复制代码
=
null ;
}
// 在左子树
if
( isLeftChild
true )
{
parent
复制代码
. left
null ;
}
else
{
parent
复制代码
. right
null ;
}
}
// 如果删除节点只有一个子节点 右节点 或者 左节点
else
if
( current . right
null )
{
if
( current
root )
{
root
复制代码
= current . left ;
}
else
if
( isLeftChild )
{
parent
复制代码
. left
current . left ;
}
else
{
parent
复制代码
. right
current . left ;
}
}
else
if
( current . left
null )
{
if
( current
root )
{
root
复制代码
= current . right ;
}
else
if
( isLeftChild )
{
parent
复制代码
. left
current . right ;
}
else
{
parent
复制代码
. right
current . right ;
}
}
// 如果删除节点左右子节点都不为空
else
if
( current . left !=
null
&& current . right !=
null )
{
// 找到删除节点的后继者
TreeNode successor
getDeleteSuccessor ( current );
if
( current
root )
{
root
复制代码
= successor ;
}
else
if
( isLeftChild )
{
parent
复制代码
. left
successor ;
}
else
{
parent
复制代码
. right
successor ;
}
successor
复制代码
. left
current . left ;
}
return current ;
}
/**
* 获取删除节点的后继者
* 删除节点的后继者是在其右节点树种最小的节点
*/
复制代码
public
TreeNode getDeleteSuccessor ( TreeNode deleteNode )
{
// 后继者
TreeNode successor
null ;
TreeNode successorParent
null ;
TreeNode current
deleteNode . right ;
while
( current !=
null )
{
successorParent
复制代码
= successor ;
successor
复制代码
= current ;
current
复制代码
= current . left ;
}
// 检查后继者(不可能有左节点树)是否有右节点树
// 如果它有右节点树,则替换后继者位置,加到后继者父亲节点的左节点.
if
( successor != deleteNode . right )
{
successorParent
复制代码
. left
successor . right ;
successor
复制代码
. right
deleteNode . right ;
}
return successor ;
}
public
void toString ( TreeNode root )
{
if
( root !=
null )
{
toString
复制代码
( root . left );
System . out . print ( "value = "
root . value +
" -> " );
toString
复制代码
( root . right );
}
}
}
/**
- 节点
*/
class
TreeNode
{
/**
* 节点值
*/
复制代码
int value ;
/**
* 左节点
*/
复制代码
TreeNode left ;
/**
* 右节点
*/
复制代码
TreeNode right ;
public
TreeNode ( int value )
{
this . value
value ;
left
复制代码
=
null ;
right
复制代码
=
null ;
}
}
面试点一:理解 TreeNode 数据结构 节点数据结构,即节点、左节点和右节点。如图
面试点二:如何确定二叉树的最大深度或者最小深度 答案:简单的递归实现即可,代码如下:
int maxDeath ( TreeNode node ){
if ( node
null ){
return
0 ;
}
int left
maxDeath ( node . left );
int right
maxDeath ( node . right );
return
Math . max ( left , right )
1 ;
}
int getMinDepth ( TreeNode root ){
if ( root
null ){
return
0 ;
}
return getMin ( root );
}
int getMin ( TreeNode root ){
if ( root
null ){
return
Integer . MAX_VALUE ;
}
if ( root . left
null && root . right
null ){
return
1 ;
}
return
Math . min ( getMin ( root . left ), getMin ( root . right ))
1 ;
}
面试点三:如何确定二叉树是否是平衡二叉树 答案:简单的递归实现即可,代码如下:
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; }
复制代码
前面面试点是 二叉树 的,后面面试点是 搜索二叉树 的。先运行搜搜二叉树代码:
public
class
BinarySearchTreeTest
{
public
static
void main ( String [] args )
{
BinarySearchTree b
new
BinarySearchTree ();
b
复制代码
. insert ( 3 ); b . insert ( 8 ); b . insert ( 1 ); b . insert ( 4 ); b . insert ( 6 );
b
复制代码
. insert ( 2 ); b . insert ( 10 ); b . insert ( 9 ); b . insert ( 20 ); b . insert ( 25 );
// 打印二叉树
b
复制代码
. toString ( b . root );
System . out . println ();
// 是否存在节点值10
TreeNode node01
b . search ( 10 );
System . out . println ( "是否存在节点值为10 => "
node01 . value );
// 是否存在节点值11
TreeNode node02
b . search ( 11 );
System . out . println ( "是否存在节点值为11 => "
node02 );
// 删除节点8
TreeNode node03
b . delete ( 8 );
System . out . println ( "删除节点8 => "
node03 . value );
b
复制代码
. toString ( b . root );
}
}
结果如下:
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 -> 面试点四:搜索二叉树如何实现插入 插入,还是比较容易理解的。就按照要求,插入到指定的位置。如果插入到叉搜索树的中间节点,那么会引起节点的动态变化。如图插入的逻辑:
值为 2 的节点开始判断
如果为空,则插入该节点
循环下面节点:
节点当前值大于,继续循环左节点
节点当前值小于,继续循环右节点
面试点五:搜索二叉树如何实现查找 算法复杂度 : O(lgN)。如图搜索及查找逻辑:
值为 2 的节点开始判断
节点当前值大于,继续循环左节点
节点当前值小于,继续循环右节点
如果值相等,搜索到对应的值,并返回
如果循环完毕没有,则返回未找到
面试点五:搜索二叉树如何实现删除 比较复杂了。相比新增、搜搜,删除需要将树重置。逻辑为:删除的节点后,其替代的节点为,其右节点树中值最小对应的节点。如图:
结果为:
三、小结 就像码出高效面试的程序媛偶尔吃一碗“老坛酸菜牛肉面”一样的味道,品味一个算法,比如 BST 的时候,总是那种说不出的味道。
面试必备小结:
树,二叉树的概念
BST 算法
如以上文章或链接对你有帮助的话
可以点击页面右上角边按钮哦,让更多的人阅读这篇文章