算法与数据结构-二叉树 讲解与java代码实现
2018-01-06 16:51
1031 查看
1. 三种遍历方式和宽度优先遍历
递归实现先序,中序,后序遍历
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class TreeToSequence { public int[][] convert(TreeNode root) { // write code here ArrayList<Integer> temp1=new ArrayList<Integer>(); ArrayList<Integer> temp2=new ArrayList<Integer>(); ArrayList<Integer> temp3=new ArrayList<Integer>(); pre(root,temp1); mid(root,temp2); post(root,temp3); int[][] result=new int[3][temp1.size()]; for(int i=0;i<temp1.size();i++){ result[0][i]=temp1.get(i); result[1][i]=temp2.get(i); result[2][i]=temp3.get(i); } return result; } public void pre(TreeNode root,ArrayList<Integer> result){ if(root==null){ return; } result.add(root.val); pre(root.left,result); pre(root.right,result); } public void mid(TreeNode root,ArrayList<Integer> result){ if(root==null){ return; } mid(root.left,result); result.add(root.val); mid(root.right,result); } public void post(TreeNode root,ArrayList<Integer> result){ if(root==null){ return; } post(root.left,result); post(root.right,result); result.add(root.val); } }
非递归实现先序,中序,后序遍历
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class TreeToSequence { public int[][] convert(TreeNode root) { // write code here ArrayList<Integer> preRes=pre(root); ArrayList<Integer> midRes=mid(root); //ArrayList<Integer> postRes=post(root); ArrayList<Integer> postRes=post_oneStack(root); int[][] result=new int[3][preRes.size()]; for(int i=0;i<preRes.size();i++){ result[0][i]=preRes.get(i); result[1][i]=midRes.get(i); result[2][i]=postRes.get(i); } return result; } //非递归的先序遍历 public ArrayList<Integer> pre(TreeNode root){ Stack<TreeNode> stack=new Stack<TreeNode>(); ArrayList<Integer> result=new ArrayList<Integer>(); stack.push(root); TreeNode cur; while(!stack.isEmpty()){ cur=stack.pop(); result.add(cur.val); if (cur.right!=null){ stack.push(cur.right); } if(cur.left!=null){ stack.push(cur.left); } } return result; } public ArrayList<Integer> mid(TreeNode root){ Stack<TreeNode> stack=new Stack<TreeNode>(); ArrayList<Integer> result=new ArrayList<Integer>(); TreeNode cur; cur=root; while(cur!=null||!stack.isEmpty()){ //将左子树依次压入栈 while(cur!=null){ stack.push(cur); cur=cur.left; } //当左子树全部压入栈后,开始从栈顶取元素并指定cur等于右子树 cur=stack.pop(); result.add(cur.val); cur=cur.right; } return result; } public ArrayList<Integer> post(TreeNode root){ Stack<TreeNode> stack1=new Stack<TreeNode>(); Stack<TreeNode> stack2=new Stack<TreeNode>(); ArrayList<Integer> result=new ArrayList<Integer>(); TreeNode cur; stack1.push(root); while(!stack1.isEmpty()){ cur=stack1.pop(); stack2.push(cur); if(cur.left!=null){ stack1.push(cur.left); } if(cur.right!=null){ stack1.push(cur.right); } } while(!stack2.isEmpty()){ cur=stack2.pop(); result.add(cur.val); } return result; } public ArrayList<Integer> post_oneStack(TreeNode root){ Stack<TreeNode> stack=new Stack<TreeNode>(); stack.push(root); ArrayList<Integer> result=new ArrayList<Integer>(); TreeNode lastNode=root,cur=null;//分别指向上次打印的节点以及当前节点 while(!stack.isEmpty()){ cur=stack.peek(); if(cur.left!=null&&cur.left!=lastNode&&cur.right!=lastNode){ stack.push(cur.left); }else if(cur.right!=null&&cur.right!=lastNode){ stack.push(cur.right); }else{ cur=stack.pop(); result.add(cur.val); lastNode=cur; } } return result; } }
宽度优先遍历(按层从左到右遍历)
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class TreePrinter { public int[][] printTree(TreeNode root) { //保存每一行的值 ArrayList<Integer> temp=new ArrayList<Integer>(); //保存总的结果的list ArrayList<ArrayList<Integer>> resList=new ArrayList<ArrayList<Integer>>(); Queue<TreeNode> queue=new LinkedList<TreeNode>();//队列,因为是按层从左到右遍历,先进先出 queue.offer(root); TreeNode cur=root,last=root,nlast=null;//分别是当前节点,本层最后一个节点,下一层最后一个节点 while(!queue.isEmpty()){ cur=queue.poll(); temp.add(cur.val); if(cur.left!=null){ queue.offer(cur.left); nlast=cur.left; } if(cur.right!=null){ queue.offer(cur.right); nlast=cur.right; } //如果当前节点为本层最后一个节点,则要把现在的节点加入结果,并令last等于nlast if(cur==last){ resList.add(temp); temp=new ArrayList<Integer>();//不能使用Clear清空,否则存进入的就变成了空,因为保存的是引用 last=nlast; } } int layers=resList.size(); int[][] result=new int[layers][]; for(int i=0;i<layers;i++){ result[i]=new int[resList.get(i).size()]; for(int j=0;j<result[i].length;j++){ result[i][j]=resList.get(i).get(j); } } return result; } }
二叉树的序列化打印:先序遍历
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class TreeToString { public String toString(TreeNode root) { // write code here Stack<TreeNode> stack=new Stack<TreeNode>(); String result=new String(); stack.push(root); TreeNode cur; while(!stack.isEmpty()){ cur=stack.pop(); if(cur==null){ result+="#!"; }else{ result+=cur.val+"!"; stack.push(cur.right); stack.push(cur.left); } } return result; } }
纸张对折n次,求折痕方向:使用中序逆序遍历,此处的逆序可以省去,因为是题目规定哪个方向为正
折纸方向打印 实现
import java.util.*; public class FoldPaper { public String[] foldPaper(int n) { // write code here ArrayList<String> temp=new ArrayList<String>(); //dir false表示"down",true表示"up" printDir(n,false,temp); int nodeSize=temp.size(); String[] result=new String[nodeSize]; for(int i=0;i<nodeSize;i++){ result[i]=temp.get(i); } return result; } //中序逆序遍历递归打印 public void printDir(int n,boolean dir,ArrayList<String> result){ if(n<1){ return; } printDir(n-1,false,result); result.add(dir?"up":"down"); printDir(n-1,true,result); } }
树上最远距离
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class LongestDistance { public int findLongest(TreeNode root) { int max=getDistance(root,0)[1]; return max; } //节点只能经过一次,那么当前节点的左右两边最远距离是最可能为最大距离的,每次要计算这个值 //同时需要返回距离头结点的单边最远距离为后续计算提供依据 //第一个返回参数为当前头结点的单边最远距离,第二个返回的参数为当前已经求得的最远距离 public int[] getDistance(TreeNode root,int max){ int[] result=new int[2]; result[1]=max; if(root==null){ result[0]=0; return result; } int[] leftRes=getDistance(root.left,max); int[] rightRes=getDistance(root.right,max); int lDistToRoot=leftRes[0]; int rDistToRoot=rightRes[0]; int twoSideDist=lDistToRoot+rDistToRoot+1; max=Math.max(leftRes[1],rightRes[1]); if(twoSideDist>max){ max=twoSideDist; } result[0]=Math.max(lDistToRoot,rDistToRoot)+1; result[1]=max; return result; } }
2.三种树及其判定方法
二叉树的子树定义平衡二叉树的定义
平衡二叉树的递归判定
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class CheckBalance { public boolean check(TreeNode root) { // write code here return getHeight(root)>=0; } //递归 求以root为头结点的树的最大高度 public int getHeight(TreeNode root){ //如果是空节点或者空树,则高度为0 if(root==null){ return 0; } int left=getHeight(root.left); int right=getHeight(root.right); //如果左子树或者右子树不平衡,则返回-1 if(left<0||right<0){ return -1; } //如果左子树或者右子树高度差大于1,则返回-1 if(Math.abs(left-right)>1){ return -1; } //返回左子树和右子树中最大的高度作为本棵树的高度 return left>right?left+1:right+1; } }
搜索二叉树
最大搜索子树
最大搜索二叉子树递归判定
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class MaxSubtree { public int nodeNum=0;//以当前节点为根节点的树的节点数 public int MAX=Integer.MAX_VALUE; public int MIN=Integer.MIN_VALUE; public int max,min;//以当前节点为根节点的树的最大最小值 public TreeNode getMax(TreeNode root) { return getInfo(root); } public TreeNode getInfo(TreeNode root){ int lNodeNum=0,rNodeNum=0;//左子树,右子树的节点数 int lMax,lMin;//左子树的最大节点值,最小节点值 int rMax,rMin; TreeNode lSearchRoot,rSearchRoot;//左右子树如果是二叉搜索树,则保存他们的头结点引用,若为null,则不是二叉搜索树 if(root==null){ nodeNum=0; max=MIN; min=MAX; return null; } lSearchRoot=getInfo(root.left); lNodeNum=nodeNum; lMax=max;lMin=min; rSearchRoot=getInfo(root.right); rNodeNum=nodeNum; rMax=max;rMin=min; min=Math.min(root.val,lMin); max=Math.max(root.val,rMax); nodeNum=Math.max(lNodeNum,rNodeNum); //当前树为二叉搜索树,要求左子树和右子树均为二叉搜索树,且以当前节点为头结点的树为二叉搜索树 //此处子树的二叉搜索树判定不能写成lSearchRoot!=null,因为要考虑到有叶节点的情况 if(lSearchRoot==root.left&&rSearchRoot==root.right&&lMax<root.val&&root.val<rMin){ nodeNum=lNodeNum+rNodeNum+1; return root; } if(lNodeNum==rNodeNum){ return lSearchRoot.val>rSearchRoot.val?lSearchRoot:rSearchRoot; } return lNodeNum>rNodeNum?lSearchRoot:rSearchRoot; } }
搜索二叉树寻找位置错误的两个节点
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class FindErrorNode { public int[] findError(TreeNode root) { // write code here ArrayList<Integer> result=new ArrayList<Integer>();//保存数值的list int[] temp=new int[2]; boolean descendTime=false; //是否曾经遇到降序:因为错位的只有2个节点,分为两种情况 //如果此时为第一次,则降序的前面个数为错位大的数,后面的数暂时存为错位小的数 //如果此时为第二次降序,则降序的后面的数为错位小的数 mid(root,result); for(int i=1;i<result.size();i++){ if(result.get(i)<result.get(i-1)){ temp[0]=result.get(i); if(descendTime==false){ descendTime=true; temp[1]=result.get(i-1); } } } return temp; } public void mid(TreeNode root,ArrayList<Integer> result){ if(root==null){ return; } mid(root.left,result); result.add(root.val); mid(root.right,result); } }
满二叉树
完全二叉树的判断
完全二叉树的判定:使用队列进行宽度优先遍历
import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class CheckCompletion { public boolean chk(TreeNode root) { // write code here Queue<TreeNode> queue=new LinkedList<TreeNode>(); queue.offer(root); TreeNode cur; boolean hasToBeLeaf=false; while(!queue.isEmpty()){ cur=queue.poll(); //如果当前节点的左孩子或者右孩子有一个为空 if(cur.left==null||cur.right==null){ //如果当前节点有右孩子却没有左孩子,则返回false,因为违背了缺少的节点全部集中在右边这一条 if(cur.left==null&&cur.right!=null) return false; //因为缺少的节点需要全部集中在右边,若当前节点只有左孩子却没有右孩子,则后继节点必须为叶节点; if(hasToBeLeaf==false) hasToBeLeaf=true; //若此节点必须为叶节点却有左孩子,则返回false else if(cur.left!=null){ return false; } }else{ queue.offer(cur.left); queue.offer(cur.right); } } return true; } }
注释和引用:
java实现:* Stack Queue * Stack<TreeNode> stack=new Stack<TreeNode>();//声明和定义 * push() pop()//入栈和出栈 * peek() //方法调用返回在这个堆栈的顶部的对象,但是不弹出 * Queue<TreeNode> queue=new LinkedList<TreeNode>();//队列的声明和定义 * offer() poll()//入队和出队 * isEmpty() //判断栈和队列是否为空 * http://www.runoob.com/java/data-queue.html 队列 菜鸟教程 * 数组的大小用length属性,list的大小用size()函数 * Arraylist<type(类名比如Integer或者String)> * List<String> temp=new ArrayList<String>();//初始化动态链表 * size()//List或者ArrayList的元素个数 * add()//添加元素 * get(i)获取元素
牛客网算法课程视频链接
相关文章推荐
- 算法与数据结构-链表 讲解与java代码实现
- 算法与数据结构-栈与队列 讲解与java代码实现
- 算法与数据结构-二分搜索 讲解与java代码实现
- 算法与数据结构-字符串 讲解与java代码实现
- 算法与数据结构-排序 讲解与java代码实现
- 算法与数据结构-动态规划 讲解与java代码实现
- 【数据结构和算法】之二叉树的java实现
- 【数据结构和算法】【二叉树】二叉树遍历的代码实现
- Java二叉树的编程实现(数据结构)和正则表达式代码实现
- 算法:二叉树的先(根)序遍历、中(根)序遍历、后(根)序遍历(递归及压栈出栈实现的非递归方式)的java代码实现
- 用java代码实现二叉树的遍历算法
- 【算法与数据结构】冒泡、插入、归并、堆排序、快速排序的Java实现代码
- 算法:二叉树的先序遍历、中序遍历、后序遍历(递归及非递归方式)的java代码实现
- java 数据结构二叉树的实现代码
- 用代码实现二叉树的遍历-Java经典面试题算法部分核心
- 线索二叉树代码实现 - 数据结构和算法49
- 关键路径(代码讲解)- 数据结构和算法68
- JAVA中的排序算法及代码实现
- 【算法】【算法】b树的实现(2)---java版代码
- 【算法】B+树的研读及实现(2)---java版核心代码