有关树的面试题:
有关树的常见问题:
-
如何得到树的节点个数?
遍历这棵树,用一个值记录节点个数即可; -
如何得到以可树的高度?
递归得到每个节点的左右子节点的高度,在加上当前节点自己,返回给上一层调用,这样就会一层一层的得到从每个叶子节点往上返回的高度,最终得到树的高度; -
如何得到一棵树的镜像?(就是每个节点的左右子节点调换位置);
采用前序、中序、后序遍历中的任何一种,从叶子节点开始交换左右节点的指针,往上实现交换指针即可; -
根据树的前序和中序遍历结果得到一棵树?
这个参考链接
/**
* 得到树的节点个数
* @return
*/
public int number1(BSTNode<Integer> root) {
return findNumber(root,0);
}
private int findNumber(BSTNode<Integer> root, int count) {
if(root == null) {
return 0;
}
count += 1;
int left = findNumber(root.getLeft(),0);
int right = findNumber(root.getRight(),0);
return left+right+count;
}
/**
* 得到树的高度
* @return
*/
public int level(BSTNode<Integer> root) {
return findLength(root,0);
}
private int findLength(BSTNode<Integer> root, int i) {
if(root == null) {
return 0;
}
int left = findLength(root.getLeft(),0);
int right = findLength(root.getRight(),0);
return left > right ? left+1 : right+1;
}
/**
* 得到一棵树的镜像
* @param root
*/
public void mirror(BSTNode<Integer> root) {
if(root == null) {
return;
}
mirror(root.getLeft());
mirror(root.getRight());
BSTNode<Integer> temp = root.getLeft();
root.setLeft(root.getRight());
root.setRight(temp);
}
下面这些是关于二叉搜索树的问题:
- 打印值在指定区间内的节点?
因为是二叉搜索树,所以注意它的父节点的值大于左子节点而小于右子节点这个条件,遍历的时候去除掉那些不需要的递归,不需要全部节点都遍历一次; - 判定一棵树是否满足二叉树?
二叉搜索树就是父节点的值大于左子节点而小于右子节点,一种方法是:中序遍历当前的树,然后判断得到的节点集合是否单调递增,但这样需要遍历整个树,所以效率不高,因此另一种方法是:我们可以在中序遍历的过程中进行判断,如果哪个节点不满足父节点的值大于左子节点而小于右子节点的条件,直接返回false就不用继续遍历了,如果每个节点都满足这个条件,那也有可能只是局部满足这个条件,但对于整棵树来说并不满足,这个时候为确保正确,需要再进行对节点集合是否单调递增的判断,代码中采用的这种方法;第三种方法是采用中序遍历,每次记录上一次遍历节点的值,因为是中序遍历,那么后面每个节点的值都应该大于上一次遍历的节点的值,并且父节点的值大于左子节点而小于右子节点,需要同时满足这两个条件才可以,否者返回false,这种方法效率更高; - 最近公共祖先?
从根节点开始往下遍历整棵树,得到包含两个节点的路径,这样就变成了求两条链表的交点的问题; - 返回一棵二叉搜索树的倒数第k个节点?
一种低效的做法是,采用一般的中序遍历(左子节点→父节点→右子节点),然后得到一个节点或者节点的值的集合,遍历这个集合取得倒数第k个节点,但这样效率较低,因为需要遍历整棵树,那么另一种方法就是采用自定义的中序遍历(右子节点→父节点→左子节点),遍历的时候记录当前遍历的节是倒数第几个,如果等于k,返回该节点即可;
/**
* 打印 begin <= root.data <= end
* @param root
* @param begin
* @param end
*/
public void printAreadDatas(BSTNode<Integer> root,int begin,int end) {
if(root == null || begin > end) {
return;
}
if(root.getData() >= begin && root.getData() <= end) {
System.out.print(root.getData() + "\t");
}
if(root.getLeft() != null && root.getLeft().getData() >= begin) {
printAreadDatas(root.getLeft(), begin, end);
}
if(root.getRight() != null && root.getRight().getData() <= end) {
printAreadDatas(root.getRight(), begin, end);
}
}
/**
* 判断一颗二叉树是否满足二叉树
*/
public boolean isBSTree(BSTNode<Integer> root) {
if(root == null) {
return true;
}
LinkedList<Integer> list = new LinkedList<>();
if(find(root,list)) {
for (int i = 1; i < list.size(); i++) {
if(list.get(i) < list.get(i-1)) {
return false;
}
}
}else {
return false;
}
return true;
}
private boolean find(BSTNode<Integer> root, LinkedList<Integer> list) {
if(root == null) {
return true;
}
if(root.getLeft() != null && root.getLeft().getData() > root.getData()) {
return false;
}
if(root.getRight() != null && root.getRight().getData() < root.getData()) {
return false;
}
boolean left = find(root.getLeft(),list);
if(!left) {
return false;
}
list.addLast(root.getData());
boolean right = find(root.getRight(),list);
return right;
}
/**
* 最近公共祖先
* @param root
* @param data1
* @param data2
* @return
*/
public int getLCA(BSTNode<Integer> root,int data1,int data2) {
if(root == null) {
return -1;
}
Stack<BSTNode<Integer>> stack1 = new Stack<>();
Stack<BSTNode<Integer>> stack2 = new Stack<>();
findPath(root,stack1,data1);
findPath(root,stack2,data2);
int length1 = stack1.size();
int length2 = stack2.size();
int length = Math.abs(length1-length2);
if(length1 > length2) {
while (length > 0) {
stack1.pop();
length--;
}
}else if(length1 < length2) {
while (length > 0) {
stack2.pop();
length--;
}
}
length = stack1.size();
while (length > 0) {
int val1 = stack1.pop().getData();
int val2 = stack2.pop().getData();
if(val1 == val2) {
return val1;
}
length--;
}
return -1;
}
/**
* 寻找包含指定值的节点
* @param root
* @param stack
* @param data
*/
private void findPath(BSTNode<Integer> root,Stack<BSTNode<Integer>> stack, int data) {
if(root == null) {
return;
}
stack.push(root);
if(root.getData() == data) {
return;
}else if(root.getData() < data) {
findPath(root.getRight(),stack,data);
}else {
findPath(root.getLeft(),stack,data);
}
}
private int count = 0;
/**
* 返回一颗二叉搜索树的倒数第k个节点 递归实现
* @param root
* @param k
* @return
*/
public BSTNode<Integer> getOrderValue(BSTNode<Integer> root,int k) {
if(root == null) {
return root;
}
BSTNode<Integer> p = getOrderValue(root.getRight(),k);
if(p != null) {
return p;
}
if(++count == k) {
return root;
}
BSTNode<Integer> q = getOrderValue(root.getLeft(),k);
if(q != null) {
return q;
}
return null;
}
/**
* 返回一颗二叉搜索树的倒数第k个节点 循环实现
* @param root
* @param k
* @return
*/
public BSTNode<Integer> getOrderValue1(BSTNode<Integer> root,int k) {
if(root == null) {
return root;
}
Stack<BSTNode<Integer>> stack = new Stack<>();
int count = 0;
BSTNode<Integer> p = root;
boolean sign = false;
while (p != null || !stack.empty()) {
if(p != null) {
stack.push(p);
p = p.getRight();
}else {
if(!sign) {
sign = true;
}
p = stack.pop();
if(sign) {
count++;
if(count == k) {
return p;
}
}
p = p.getLeft();
}
}
return null;
}
关于AVL树的:
- 判断以可二叉搜索树是否是AVL树?
AVL树就是一棵平衡的二叉搜索,也就是它的任何一个节点的左右子树高度差不会超过1,也就是这个问题比较的是树的左右子树的高度问题;
/**
* 判断一棵二叉搜索树是否是AVL树
* @param root
* @return
*/
public boolean isAVL(BSTNode<T> root) {
if(root == null) {
return true;
}
boolean left = isAVL(root.getLeft());
boolean right = isAVL(root.getRight());
int leftLength = getLength(root.getLeft());
int rightLength = getLength(root.getRight());
if(Math.abs(leftLength-rightLength) > 1) {
return false;
}
return left && right;
}
/**
* 获取root节点树的高度
* @param root
* @return
*/
private int getLength(BSTNode<T> root) {
if(root == null) {
return 0;
}
int left = getLength(root.getLeft());
int right = getLength(root.getRight());
return Math.max(left,right)+1;
}