知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!
目录
BST二叉搜索树是面试中常考的问题,因为不涉及旋转操作和节点着色,因此比AVL和红黑树实现起来要简单很多,成为了笔试面试中写代码常见的考点。这篇文章分享一下BST树以及常见的BST树相关的笔试面试常考题目。
二分查找
对于一组有序的序列,进行搜索的时候可以采用二分搜索来提高效率,对比线性搜索的时间复杂度是O(n),对于有序序列的二分搜索时间复杂度是O( log 2 n \log_2n log2n),因此搜索效率比较高,下面提供递归以及非递归的二分搜索代码实现:
非递归版本
/**
* 二分查找的非递归实现,在有序的list集合元素中,进行二分搜索,查找val值
* @param list
* @return
*/
private static <T extends Comparable<T>>
T nonrecur_binarysearch(List<T> list, T val) {
int first = 0;
int last = list.size()-1;
int middle = 0;
T data = null;
while(first <= last){
middle = (first + last) / 2;
data = list.get(middle);
if(val.compareTo(data) < 0){
last = middle-1;
} else if(val.compareTo(data) > 0){
first = middle+1;
} else {
return data;
}
}
return null;
}
递归版本
/**
* 二分查找的递归实现,在有序的list集合元素中,进行二分搜索,查找val值
* @param list
* @param val
* @return
*/
private static <T extends Comparable<T>>
T recur_binarysearch(List<T> list, T val) {
return recur_binarysearch(list, 0, list.size()-1, val);
}
/**
* 二分查找的递归具体实现过程
* @param list
* @param i
* @param j
* @param val
* @return
*/
private static <T extends Comparable<T>>
T recur_binarysearch(List<T> list, int i, int j, T val) {
if(i > j){
return null;
}
int middle = (i + j) / 2;
T data = list.get(middle);
if(val.compareTo(data) < 0){
return recur_binarysearch(list, i, middle-1, val);
} else if(val.compareTo(data) > 0){
return recur_binarysearch(list, middle+1, j, val);
} else {
return data;
}
}
测试代码如下:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Random rand = new Random(50);
for(int i=0; i<20; ++i){
list.add(rand.nextInt(100));
}
Collections.sort(list);
System.out.println("排序后的元素序列:" + list);
Integer data = nonrecur_binarysearch(list, 7);
System.out.println(data);
data = recur_binarysearch(list, 28);
System.out.println(data);
}
BST二叉搜索树
上面二分搜索的过程就是BST树搜索的过程,BST树的每一个节点最多有两个孩子,而且左孩子的值 < 父节点的值 < 右孩子的值,下面定义BST树相关的类:
/**
* BST树节点的实现
* @param <T>
*/
class BSTNode<T extends Comparable<T>>{
private T data;
private BSTNode<T> left;
private BSTNode<T> right;
public BSTNode(T data) {
this(data, null, null);
}
public BSTNode(T data, BSTNode<T> left, BSTNode<T> right) {
this.data = data;
this.left = left;
this.right = right;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public BSTNode<T> getLeft() {
return left;
}
public void setLeft(BSTNode<T> left) {
this.left = left;
}
public BSTNode<T> getRight() {
return right;
}
public void setRight(BSTNode<T> right) {
this.right = right;
}
}
/**
* BST树的实现
* @param <T>
*/
class BST<T extends Comparable<T>>{
private BSTNode<T> root; // 指向BST树的根节点
public BST() {
this.root = null;
}
}
BST树常见代码题
BST树插入,删除,查询操作,递归和非递归实现
BST树的插入操作,递归和非递归代码实现:
/**
* BST树的递归插入函数接口
* @param val
*/
public void insert(T val){
this.root = insert(root, val);
}
/**
* BST树的递归插入具体实现函数
* @param root
* @param val
* @return
*/
private BSTNode<T> insert(BSTNode<T> root, T val) {
if(null == root){
return new BSTNode<>(val);
}
if(root.getData().compareTo(val) > 0){
root.setLeft(insert(root.getLeft(), val));
} else if(root.getData().compareTo(val) < 0){
root.setRight(insert(root.getRight(), val));
} else {
;
}
return root;
}
/**
* 非递归实现BST树的插入操作
* @param val
*/
public void noncur_insert(T val){
if(null == this.root){
this.root = new BSTNode<T>(val);
return;
}
BSTNode<T> parent = null;
BSTNode<T> cur = this.root;
while(cur != null){
parent = cur;
if(cur.getData().compareTo(val) > 0){
cur = cur.getLeft();
} else if(cur.getData().compareTo(val) < 0){
cur = cur.getRight();
} else{
return;
}
}
if(parent.getData().compareTo(val) > 0){
parent.setLeft(new BSTNode<T>(val));
} else{
parent.setRight(new BSTNode<T>(val));
}
}
BST树的删除操作,递归和非递归代码实现:
/**
* 递归删除val元素的函数接口
* @param val
*/
public void remove(T val){
this.root = remove(root, val);
}
/**
* 递归实现BST删除函数
* @param root
* @param val
* @return
*/
private BSTNode<T> remove(BSTNode<T> root, T val) {
if(root == null){
return null;
}
if(root.getData().compareTo(val) > 0){
root.setLeft(remove(root.getLeft(), val));
} else if(root.getData().compareTo(val) < 0){
root.setRight(remove(root.getRight(), val));
} else {
if(root.getLeft() != null
&& root.getRight() != null){
BSTNode<T> pre = root.getLeft();
while(pre.getRight() != null){
pre = pre.getRight();
}
root.setData(pre.getData());
root.setLeft(remove(root.getLeft(), pre.getData()));
} else if(root.getLeft() != null){
return root.getLeft();
} else if(root.getRight() != null) {
return root.getRight();
} else {
return null;
}
}
return root;
}
/**
* BST树的非递归删除
* @param val
*/
public void noncur_remove(T val){
BSTNode<T> parent = null;
BSTNode<T> cur = root;
while(null != cur){
if(cur.getData().compareTo(val) > 0){
parent = cur;
cur = cur.getLeft();
} else if(cur.getData().compareTo(val) < 0){
parent = cur;
cur = cur.getRight();
} else {
break;
}
}
if(null == cur){
return;
}
if(null != cur.getLeft() && null != cur.getRight()){
// 用前驱结点代替删除节点,然后删除前驱结点
BSTNode<T> old = cur;
parent = cur;
cur = cur.getLeft();
while(null != cur.getRight()){
parent = cur;
cur = cur.getRight();
}
old.setData(cur.getData());
}
// 删除cur节点
BSTNode<T> child = cur.getLeft();
if(null == child){
child = cur.getRight();
}
if(null == parent){
this.root = child;
} else if(parent.getLeft() == cur){
parent.setLeft(child);
} else {
parent.setRight(child);
}
}
BST树的查询操作,递归和非递归代码实现:
/**
* 非递归查询元素val
* @param val
* @return
*/
public BSTNode<T> noncur_query(T val){
BSTNode<T> cur = root;
while(cur != null){
if(cur.getData().compareTo(val) > 0){
cur = cur.getLeft();
} else if(cur.getData().compareTo(val) < 0){
cur = cur.getRight();
} else {
return cur;
}
}
return null;
}
/**
* 递归查找元素val
* @return
*/
public BSTNode<T> query(T val){
return query(root, val);
}
private BSTNode<T> query(BSTNode<T> root, T val) {
if(root == null)
return null;
if(root.getData().compareTo(val) > 0){
return query(root.getLeft(), val);
} else if(root.getData().compareTo(val) < 0){
return query(root.getRight(), val);
} else {
return root;
}
}
BST树前序,中序,后序,层序遍历的递归和非递归实现
BST前序遍历:
/**
* BST树的前序遍历 VLR
*/
public void preOrder(){
preOrder(root);
System.out.println();
}
private void preOrder(BSTNode<T> root) {
if(null != root){
System.out.print(root.getData() + " ");
preOrder(root.getLeft());
preOrder(root.getRight());
}
}
/**
* 非递归实现前序遍历 VLR
*/
public void nonrecur_preOrder(){
if(this.root == null){
return;
}
LinkedList<BSTNode<T>> stack = new LinkedList<>();
BSTNode<T> top = this.root;
stack.push(top);
while(!stack.isEmpty()){
top = stack.pop();
System.out.print(top.getData() + " ");
if(top.getRight() != null){
stack.push(top.getRight());
}
if(top.getLeft() != null){
stack.push(top.getLeft());
}
}
System.out.println();
}
BST中序遍历:
/**
* BST树中序遍历 LVR
*/
public void inOrder(){
inOrder(root);
System.out.println();
}
private void inOrder(BSTNode<T> root) {
if(null != root){
inOrder(root.getLeft());
System.out.print(root.getData() + " ");
inOrder(root.getRight());
}
}
/**
* 中序遍历非递归实现
*/
public void nonrecur_inOrder(){
if(this.root == null){
return;
}
LinkedList<BSTNode<T>> stack = new LinkedList<>();
BSTNode<T> top = this.root;
while(!stack.isEmpty() || top != null){
if(top != null){
stack.push(top);
top = top.getLeft();
} else {
top = stack.pop();
System.out.print(top.getData() + " ");
top = top.getRight();
}
}
System.out.println();
}
BST后序遍历:
/**
* BST树后序遍历 LRV
*/
public void lastOrder(){
lastOrder(root);
System.out.println();
}
private void lastOrder(BSTNode<T> root) {
if(null != root){
lastOrder(root.getLeft());
lastOrder(root.getRight());
System.out.print(root.getData() + " ");
}
}
/**
* 非递归实现后序遍历 LRV
*/
public void nonrecur_lastOrder(){
if(this.root == null){
return;
}
LinkedList<BSTNode<T>> stack = new LinkedList<>();
LinkedList<BSTNode<T>> stack2 = new LinkedList<>();
BSTNode<T> top = this.root;
stack.push(top);
while(!stack.isEmpty()){
top = stack.pop();
stack2.push(top);
if(top.getLeft() != null){
stack.push(top.getLeft());
}
if(top.getRight() != null){
stack.push(top.getRight());
}
}
while(!stack2.isEmpty()){
System.out.print(stack2.pop().getData() + " ");
}
System.out.println();
}
BST层序遍历:
/**
* 递归实现层序遍历
*/
public void levelOrder(){
int height = level();
for (int i = 0; i < height; i++) {
levelOrder(root, i);
}
System.out.println();
}
private void levelOrder(BSTNode<T> root, int k) {
if(root == null){
return;
}
if(k == 0){
System.out.print(root.getData() + " ");
} else {
levelOrder(root.getLeft(), k-1);
levelOrder(root.getRight(), k-1);
}
}
/**
* 非递归实现层序遍历
*/
public void nonrecur_levelOrder(){
if(this.root == null){
return;
}
LinkedList<BSTNode<T>> queue = new LinkedList<>();
BSTNode<T> cur = null;
queue.offer(this.root);
while(!queue.isEmpty()){
cur = queue.poll();
System.out.print(cur.getData() + " ");
if(cur.getLeft() != null){
queue.offer(cur.getLeft());
}
if(cur.getRight() != null){
queue.offer(cur.getRight());
}
}
System.out.println();
}
BST求树的高度,节点元素个数
BST树的高度:
/**
* 递归求BST树的高度的函数接口
* @return
*/
public int level(){
return level(root);
}
/**
* 返回BST树的高度
* @param root
* @return
*/
private int level(BSTNode<T> root) {
if(root == null)
return 0;
int left = level(root.getLeft());
int right = level(root.getRight());
return (left > right ? left : right) + 1;
}
BST树求节点个数:
/**
* 返回BST树节点的个数的函数接口
* @return
*/
public int number(){
return number(root);
}
/**
* 求BST树节点个数的具体实现函数
* @param root
* @return
*/
private int number(BSTNode<T> root) {
if(root == null){
return 0;
}
return 1 + number(root.getLeft()) + number(root.getRight());
}
BST树区间元素查找
面试题,在BST树中,查找满足某一个区间元素范围的值,代码实现:
/**
* 把BST树中满足[begin, end]区间的元素打印出来
* @param begin
* @param end
*/
public void findAreaDatas(T begin, T end){
findAreaDatas(this.root, begin, end);
System.out.println();
}
private void findAreaDatas(BSTNode<T> root, T begin, T end) {
if(root == null){
return;
}
if(root.getData().compareTo(begin) > 0){ // 优化二叉树遍历
findAreaDatas(root.getLeft(), begin, end);
}
if(root.getData().compareTo(begin) >= 0
&& root.getData().compareTo(end) <= 0){
System.out.print(root.getData() + " ");
}
if(root.getData().compareTo(end) < 0){ // 优化二叉树遍历
findAreaDatas(root.getRight(), begin, end);
}
}
判断二叉树是否是一颗BST树
/**
* 判断一颗二叉树是否是BST树
* @return
*/
BSTNode<T> pre = null; // pre保存中序遍历前一个节点的值
public boolean isBSTree(){
return isBSTree(this.root);
}
/**
* @param root
* @return
*/
private boolean isBSTree(BSTNode<T> root) {
if(root == null){
return true;
}
if(!isBSTree(root.getLeft())){
return false;
}
if(pre != null && root.getData().compareTo(pre.getData()) < 0){
return false;
}
pre = root;
return isBSTree(root.getRight());
}
BST求子树问题
/**
* 判断childTree是否是当前BST的子树
* @param childTree
* @return
*/
public boolean isChildTree(BST<T> childTree){
BSTNode<T> cur = query(childTree.root.getData());
if(cur != null){
return isChildTree(cur, childTree.root);
}
return false;
}
private boolean isChildTree(BSTNode<T> father, BSTNode<T> child) {
if(father == null && child == null){
return true;
}
if(father == null){
return false;
}
if(child == null){
return true;
}
if(father.getData().compareTo(child.getData()) != 0){
return false;
}
return isChildTree(father.getLeft(), child.getLeft())
&& isChildTree(father.getRight(), child.getRight());
}
BST的LCA问题:求寻找最近公共祖先节点
/**
* 获取BST树中两个节点的最近公共祖先
* @param a
* @param b
* @return
*/
public T getLCA(T a, T b){
return getLCA(root, a, b);
}
private T getLCA(BSTNode<T> root, T a, T b) {
if(root == null){
return null;
}
if(root.getData().compareTo(a) > 0
&& root.getData().compareTo(b) > 0){
return getLCA(root.getLeft(), a, b);
} else if(root.getData().compareTo(a) < 0
&& root.getData().compareTo(b) < 0){
return getLCA(root.getRight(), a, b);
} else {
return root.getData();
}
}
BST树的镜像反转问题
/**
* BST树镜像翻转问题
*/
public void mirror(){
mirror(root);
}
private void mirror(BSTNode<T> root) {
if(root == null){
return;
}
BSTNode<T> left = root.getLeft();
root.setLeft(root.getRight());
root.setRight(left);
mirror(root.getLeft());
mirror(root.getRight());
}
已知BST树的前序遍历和中序遍历,重建BST树
/**
* 已知前序遍历和中序遍历,如何重建BST树
* @param pre
* @param in
*/
public void rebuild(T[] pre, T[] in){
this.root = rebuild(pre, in, 0, pre.length-1, 0, in.length-1);
}
private BSTNode<T> rebuild(T[] pre, T[] in, int i, int j, int m, int n) {
if(i > j || m > n)
return null;
BSTNode<T> node = new BSTNode<>(pre[i]);
for(int k=m; k<=n; ++k) {
if(pre[i].compareTo(in[k]) == 0){
node.setLeft(rebuild(pre, in, i+1, i+(k-m), m, k-1));
node.setRight(rebuild(pre, in, i+(k-m)+1, j, k+1, n));
return node;
}
}
return node;
}
判断一颗BST树是否是平衡树
平衡树的概念是,树中每个节点的左右子树高度差不超过1,因此可以对BST树进行递归,在递归回溯的时候,从叶子节点向上逐渐回溯到根节点,判断每一层是否有节点失衡,代码如下:
/**
* 判断一个BST树是否是AVL树
* @return 是AVL树返回true,否则返回false
*/
public boolean isAVLTree(){
int l = isAVLTree(this.root);
return l != -1;
}
private int isAVLTree(BSTNode<T> root) {
if(root == null){
return 0;
} else {
int left = isAVLTree(root.getLeft());
int right = isAVLTree(root.getRight());
// 上面两行是BST树的递归遍历调用,下面代码在递归回溯的时候判断节点是否失衡
if(left == -1 || right == -1
||Math.abs(left-right) > 1){
return -1;
}
return left > right ? left+1 : right+1;
}
}