目录
二叉树
什么是二叉树?
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”和“右子树”,左子树和右子树同时也是二叉树。二叉树的子树有左右之分,并且次序不能任意颠倒。二叉树是递归定义的,所以一般二叉树的相关题目也都可以使用递归的思想来解决,当然也有一些可以使用非递归的思想解决,我下面列出的一些算法有些采用了递归,有些是非递归的。
什么是二叉排序树?
二叉排序树又叫二叉查找树或者二叉搜索树,它首先是一个二叉树,而且必须满足下面的条件:
1)若左子树不空,则左子树上所有结点的值均小于它的根节点的值;
2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值
3)左、右子树也分别为二叉排序树
4)没有键值相等的节点(?可能是因为不好处理键值相等的节点到底是左节点还是右节点吧)
二叉树的数据结构定义
public class TreeNode<T> {
public T val;
public TreeNode<T> left;
public TreeNode<T> right;
public TreeNode(T val) {
this.val = val;
this.left = null;
this.right = null;
}
}
二叉树的各种遍历
各个遍历的递归版:
public void preOrder(TreeNode<T> node){
if (node == null)
return;
//前序这里执行处理(中左右)
System.out.println(node.val);
preOrder(node.left,SB);
//中序在这里(左中右)
//System.out.println(node.val);
preOrder(node.right,SB);
//后序在这里(左右中)
//System.out.println(node.val);
}
}
前序遍历非递归版
public void preorderIteratively(TreeNode<T> node){
if(node==null)
return;
//stack栈顶元素永远为cur的父节点
Stack<TreeNode<T>> stack = new Stack();
TreeNode<T> cur = node;
while(cur!=null || !stack.isEmpty()){
if(cur!=null){
System.out.println(cur.val);
stack.push(cur);
cur = cur.left;
}
else{
cur = stack.pop().right;
}
}
}
中序遍历非递归版
public void inorderIteratively(TreeNode<T> node){
//stack栈顶元素永远为cur的父节点
Stack<TreeNode<T>> stack = new Stack();
TreeNode<T> cur = node;
while(cur!=null || !stack.isEmpty()){
if(cur!=null){
stack.push(cur);
cur = cur.left;
}
else{
System.out.println(stack.peek().val);
cur = stack.pop().right;
}
}
}
后序遍历非递归版(较难理解)
public void postorderIteratively(TreeNode<T> node){
//stack栈顶元素永远为cur的父节点
//prevVisted用于区分是从左子树还是右子树返回的
Stack<TreeNode<T>> stack = new Stack();
TreeNode<T> cur = node;
TreeNode<T> prevVisted = null;
while(cur!=null || !stack.isEmpty()){
if(cur!=null){
stack.push(cur);
cur = cur.left;
}
else{
cur = stack.peek().right;
if(cur!=null && cur!=prevVisted){
stack.push(cur);
cur = cur.left;
}
else{
prevVisted = stack.pop();
System.out.println(prevVisted.val);
cur = null;
}
}
}
}
方便任意转换的非递归版遍历
public static String preorderTraversal(TreeNode root) {
if (root == null) return null;
List list = new ArrayList();
Stack<Command> stack = new Stack();
stack.push(new Command("go",root));
while (!stack.isEmpty()){
Command command = stack.pop();
if (command.s.equals("print")){
list.add(command.node.val);
}else { //go
//这里是后序遍历
//stack.push(new Command("print",command.node));//这里是前序遍历
if (command.node.right!=null)
stack.push(new Command("go",command.node.right));
//这里是中序遍历
//stack.push(new Command("print",command.node));//这里是前序遍历
if (command.node.left!=null)
stack.push(new Command("go",command.node.left));
//这里是前序遍历
stack.push(new Command("print",command.node));
}
}
return list.toString();
}
从上到下不分行的层序遍历
public String 层序遍历() {
StringBuilder SB = new StringBuilder("层序遍历:[");
Queue<TreeNode<T>> queue = new LinkedList();
queue.offer(this);
TreeNode<T> temp;
while(!queue.isEmpty()){
temp = queue.poll();//插入并删除此队列的头
SB.append(temp.val);
SB.append(",");
if(temp.left!=null)
queue.offer(temp.left);
if(temp.right!=null)
queue.offer(temp.right);
}
SB.deleteCharAt(SB.lastIndexOf(","));
SB.append("]");
return SB.toString();
}
从底到上分行的层序遍历
public static void traverseReverse(TreeNode node){
if (node == null)
return;
Queue<TreeNode> queue = new LinkedList();
queue.offer(node);
ArrayList<ArrayList<Integer>> list = new ArrayList();
int index = 0;
while (!queue.isEmpty()){
list.add(index,new ArrayList());
ArrayList innerList = list.get(index++);
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode cur = queue.poll();
innerList.add(cur.val);
if (cur.left!=null){
queue.offer(cur.left);
}
if (cur.right!=null){
queue.offer(cur.right);
}
}
}
for (int i = list.size()-1; i >= 0 ; i--) {
ArrayList innerList = list.get(i);
for (int j = 0; j < innerList.size(); j++) {
System.out.print(innerList.get(j));
}
System.out.println();
}
}
二叉树的最小深度
public static int treeDepth(TreeNode root) {
if (root == null)
return 0;
int left = treeDepth(root.left);
int right = treeDepth(root.right);
if (left==0||right==0){
return left+right+1;
}
return 1+Math.min(left,right);
}
判断是否为平衡二叉树
/*
* 采用递归的做法,效率不高,节点会被重复计算
*/
private static boolean isBalanced(TreeNode<Integer> root) {
if (root==null) {
return true;
}
int left = treeDepth(root.left);
int right = treeDepth(root.right);
if(left-right>1 ||left-right<-1){
return false;
}
return isBalanced(root.left)&&isBalanced(root.right);
}
/*
* 采用后序遍历的方法,每个节点只算一次
*/
public static boolean isBalanced2(TreeNode<Integer> node){
if(node==null)
return true;
int depth[] = new int[1];
return isBalanced2Core(node,depth);
}
private static boolean isBalanced2Core(TreeNode<Integer> root, int[] depth) {
if (root==null) {
return true;
}
int left[] = new int[1];
int right[] = new int[1];
if (isBalanced2Core(root.left,left)&&isBalanced2Core(root.right,right)) {
if ((left[0]- right[0]<=1)||(left[0]- right[0]>=-1)) {
depth[0] = 1+ ((left[0]>right[0])?left[0]:right[0]) ;
return true;
}
}
return false;
}
按之字形打印二叉树
//用两个栈
public static void ZhiPrint(TreeNode root){
if(root == null)return;
//用于保存 左右 子节点
Stack<TreeNode<Integer>> stack1 = new Stack();
//用户保存 右左 子节点
Stack<TreeNode<Integer>> stack2 = new Stack();
TreeNode<Integer> temp ;
stack2.push(root);
while(!stack1.isEmpty()||!stack2.isEmpty()){
while(!stack1.isEmpty()){
temp = stack1.pop();
System.out.print(temp.val);
if(temp.right!=null)stack2.push(temp.right);
if(temp.left!=null)stack2.push(temp.left);
}
System.out.println();
while(!stack2.isEmpty()){
temp = stack2.pop();
System.out.print(temp.val);
if(temp.left!=null)stack1.push(temp.left);
if(temp.right!=null)stack1.push(temp.right);
}
System.out.println();
}
}
二叉树的直径
直径定义:从一个子节点到另外一个子节点的最长长度
private static int Diameter;
public static int diameterOfBinaryTree(TreeNode root) {
if (root == null)
return 0;
maxDepth(root);
return Diameter;
}
private static int maxDepth(TreeNode root) {
if (root == null)
return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
Diameter = Math.max(Diameter,left+right);
return Math.max(left,right)+1;
}
是
二叉树的镜像
public void mirrorRecursively(TreeNode<Integer> root) {
if(root == null)
return;
if(root.left == null && root.right == null){
return;
}
//执行交换左右子树
TreeNode<Integer> tempNode = root.left;
root.left = root.right;
root.right = tempNode;
if(root.left!=null){
mirrorRecursively(root.left);
}if(root.right!=null){
mirrorRecursively(root.right);
}
}
判断是否为对称二叉树
public boolean isSymmetrical(TreeNode<Integer> root){
if(root==null)
return false;
if(root.left==null && root.right==null)
return true;
if(root.left==null || root.right==null)
return false;
return isSymmetrical(root.left,root.right);
}
public boolean isSymmetrical(TreeNode<Integer> root1, TreeNode<Integer> root2){
if(root1==null && root2==null)
return true;
if(root1==null || root2==null)
return false;
if(!root1.val.equals(root2.val))
return false;
return isSymmetrical(root1.left,root2.right) &&
isSymmetrical(root1.right,root2.left);
}