最近在刷算法题,抽空把二叉树的一些最基本算法进行总结。所有函数都基于以下树的定义:
//数据结构定义 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } }
1. 二叉树的三种遍历方式:前序,中序,后序。
先序是先遍历根,再遍历左子树,再遍历右子树;
中序是先遍历左子树,再遍历根,再遍历右子树;
后序是先遍历右子树,再遍历根,再遍历左子树;
//先序遍历算法 public static void preOrderTraverse(TreeNode root){ if(root == null) return; preOrderTraverse(root.left); System.out.println(root.val); preOrderTraverse(root.right); } //中序遍历算法 public static void preOrderTraverse(TreeNode root){ if(root == null) return; <span style="white-space:pre"> </span>System.out.println(root.val);
<span style="white-space:pre"> </span>preOrderTraverse(root.left);
<span style="white-space:pre"> </span>preOrderTraverse(root.right);
}
}//后序遍历算法 public static void preOrderTraverse(TreeNode root){ if(root == null) return; preOrderTraverse(root.left); preOrderTraverse(root.right); System.out.println(root.val);
2. 找出根节点到每个叶子节点的路径。
public static void PrintList(ArrayList<TreeNode> list){
for(int i=0;i<list.size();i++)
System.out.print(list.get(i).val+" ");
System.out.println();
}
public static boolean isParent(TreeNode parent,TreeNode child){ //判断是否为父子关系
if(parent == null || child == null)
return false;
if(child == parent.left || child == parent.right)
return true;
return false;
}
public static void getPath(TreeNode root) {
if(root == null) return;
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList<TreeNode> list = new ArrayList<TreeNode>(); //存储路径
stack.push(root);
while(!stack.isEmpty()){
TreeNode temp = stack.pop();
list.add(temp);
if(temp.right != null)
stack.push(temp.right);
if(temp.left != null)
stack.push(temp.left);
if (temp.left == null & temp.right == null) { //如果是叶子节点输入路径
PrintList(list);
while ((!stack.isEmpty()) && (!list.isEmpty()) && (!isParent(list.get(list.size() - 1), stack.peek())))
list.remove(list.size() - 1);
}
}
}
3. 求树的深度
int maxDepth(TreeNode* root) {
int deep = 0;
if(root == NULL)
return 0;
if(root->left == NULL && root->right == NULL)
return 1;
if(root)
{
int ldeep = maxDepth(root->left);
int rdeep = maxDepth(root->right);
deep = (ldeep > rdeep ? ldeep:rdeep ) + 1;
}
return deep;
}
4. 将二叉树反转,每一层的左右子树交换。
TreeNode* invertTree(TreeNode* root) {
if(root == NULL)
return root;
else
{
TreeNode *temp = root->left;
root->left = invertTree(root->right);
root->right = invertTree(temp);
}
return root;
}
5. 判断两颗二叉树是否相等,即结构相等,数值相等。
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==NULL && q == NULL)
return 1;
if(p==NULL || q == NULL)
return 0;
if(p->val == q->val) //P树的左、右子树和Q的左、右子树分别相等
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
else
return 0;
}
6. 二叉搜索树的最近公共父节点。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root== null || p==null ||q==null)
return null;
//如果一个比根节点大,一个比根节点小,则直接返回根节点</span>
if((p.val<= root.val && q.val>=root.val) || (p.val>=root.val && q.val<=root.val)){
return root;
} //如果都比根节点小,则将根节点的左孩子作为新的根节点</span>
else if(p.val< root.val && q.val<root.val){
return lowestCommonAncestor(root.left,p,q);
} //如果都比根节点大,则将根节点的右孩子作为新的根节点
else{
return lowestCommonAncestor(root.right,p,q);
}
}
7. 二叉树是否高度平衡,即左子树和右子树的高度差距不大于1.
public int getDepth(TreeNode root){
if(root == null) return 0;
int ld = getDepth(root.left);
int rd = getDepth(root.right);
return 1 + Math.max(ld, rd);
}
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
if(root.left == null && root.right == null) return true;
if(Math.abs(getDepth(root.left) - getDepth(root.right)) > 1)
return false; //左子树和右子树高度相差不超过1
return isBalanced(root.left) & isBalanced(root.right);
}
8.判断一个二叉树是否对称,即左右子树以根节点为对称轴。
public boolean isRight(TreeNode left,TreeNode right){
if(left == null && right == null) return true;
if((left == null && right != null) || (left != null && right == null)) return false;
if(left.val != right.val)
return false;
else //左子树的左孩子和右子树的右孩子相等,左子树的右孩子和右子树的左孩子相等
<span style="white-space:pre"> </span>return isRight(left.left,right.right) && isRight(left.right,right.left);
}
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return isRight(root.left,root.right);
}
9. 树按层次遍历,放入一个List<List<Integer>>中,即每个小list中放树的一层的数值。
public static void getList(TreeNode root, List<List<Integer>> list,int height){
if(root == null) return;
if(height >= list.size())
list.add(new ArrayList<Integer>());
list.get(height).add(root.val); //假设提前知道该节点在那一层,直接加入到List中,非常巧的思路</span>
getList(root.left, list,height+1);
getList(root.right, list,height+1);
}
public static List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
getList(root,list,0);
return list;
}
本人认为树的很多算法都可以巧妙的用递归实现,先把基本的算法都练熟了,经常温故,遇到新的题目时,都是基础题的变形,以不变应万变。