1、二叉树的建立
首先,定义数组存储树的data,然后使用list集合将所有的二叉树结点都包含进去,最后给每个父亲结点赋予左右孩子。
需要注意的是:最后一个父亲结点需要单独处理
1 public static TreeNode root; 2 //建立二叉树内部类 3 class TreeNode{ 4 public Object data; //携带变量 5 public TreeNode lchild,rchild; //左右孩子 6 public TreeNode() { 7 data = null; 8 lchild = null; 9 rchild = null; 10 } 11 public TreeNode(Object data) { 12 this.data = data; 13 } 14 public void setLeft(TreeNode left) 15 { 16 this.lchild = left; 17 } 18 public void setRight(TreeNode right) 19 { 20 this.rchild = right; 21 } 22 } 23 //建立二叉树,通过List作为中间过渡量 24 public void CreatBinTree(int []datas,Listnodelist) { 25 for(int i=0;i ) 26 { 27 TreeNode aNode = new TreeNode(datas[i]); 28 nodelist.add(aNode); 29 } 30 //给所有父亲结点设定子节点 31 for(int index = 0;index ) 32 { 33 //在起始结点为0时,为N的父亲结点他的左孩子为2*N+1,右孩子为2*N+2 34 nodelist.get(index).lchild = nodelist.get(2*index+1); 35 nodelist.get(index).rchild = nodelist.get(2*index+2); 36 } 37 //单独处理最后一个父亲结点 38 int index = nodelist.size()/2-1; 39 nodelist.get(index).lchild = nodelist.get(2*index+1); 40 if(nodelist.size()%2==1) 41 nodelist.get(index).rchild = nodelist.get(2*index+2); 42 }
2、先序遍历
2.1 递归方法
//先序遍历,递归操作 public void PreOrder(TreeNode root) { if(root == null) return ; System.out.print(root.data+" "); PreOrder(root.lchild); PreOrder(root.rchild); }
2.2 非递归操作,使用栈(两种方法)
本人认为第一种方法相对容易理解,较为简单
方法一:
思想:
(1)若栈非空或者结点非空,则进入循环
(2)若结点非空,读取该节点,并将结点压入栈中,结点向左孩子移动,移到最左孩子
(3)若栈非空,取出栈顶元素,此时父节点已读,所以移向右孩子
****************核心为:边读取左结点变将其压入栈中,左孩子对下一级来说上也代表父亲结点,所以之后可以直接读取右孩子。*******************
/* * 方法一:先序遍历,使用栈操作,相对较简单 * 思想: * (1)若栈非空或者结点非空,则进入循环 * (2)若结点非空,读取该节点,并将结点压入栈中,结点向左孩子移动,移到最左孩子 * (3)若栈非空,取出栈顶元素,此时父节点已读,所以移向右孩子 * 核心为:边读取左结点变将其压入栈中,左孩子对下一级来说上也代表父亲结点,所以之后可以直接读取右孩子。 */ public void preOrder1() { Stackstack = new Stack<>(); TreeNode node = root; while(!stack.isEmpty()||node!=null) { while(node!=null) { System.out.print(node.data+" "); //访问该节点 stack.push(node); node = node.lchild; } if(!stack.isEmpty()) { node = stack.pop(); node = node.rchild; } } }
方法二:
思想:
(1)首先将根节点入栈
(2)判断非空,将结点从栈中取出并访问
(3)依次访问栈中的左孩子,并将右孩子放入栈中,结点不断往左孩子移动
(4)重复步骤(2)(3),直到栈为空
/* * 方法二:先序遍历,使用栈操作,相对较麻烦 * 思想: * (1)首先将根节点入栈 * (2)判断非空,将结点从栈中取出并访问 * (3)依次访问栈中的左孩子,并将右孩子放入栈中,结点不断往左孩子移动 * (4)重复步骤(2)(3),直到栈为空 */ public void preOrder2() throws Exception { TreeNode pNode = root; if(pNode!=null) //首先判断根结点是否为空 { Stackastack = new Stack<>(); //构造栈操作 astack.push(pNode); //将根节点压入栈中 while(!astack.isEmpty()) //循环操作直到栈中没有结点存在,即最右结点访问完毕 { pNode = astack.pop(); //首先将结点从栈中取出 System.out.print(pNode.data+" "); //访问该节点 while(pNode!=null) //若该结点不为空 { if(pNode.lchild!=null) //访问左子树 System.out.print(pNode.lchild.data+" "); if(pNode.rchild!=null) //将右子树压入栈中 astack.push(pNode.rchild); pNode = pNode.lchild; //进入到下一个左子树中 } } } }
3、中序遍历
3.1 递归操作
//中序遍历,递归操作 public void inOrder(TreeNode root) { if(root==null) return ; inOrder(root.lchild); System.out.print(root.data+" "); inOrder(root.rchild); }
3.2 非递归操作,栈
思想:
* (1)若栈非空或者结点非空,则进入循环
* (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边
* (3)若栈非空,则取出栈顶元素,并读取访问数据,而后结点向右孩子移动
/* * 中序遍历,使用栈操作 * 思想: * (1)若栈非空或者结点非空,则进入循环 * (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边 * (3)若栈非空,则取出栈顶元素,并读取访问数据,而后结点向右孩子移动 */ public void inOrder1() throws Exception { TreeNode node = root; Stackstack = new Stack<>(); while(node!=null||!stack.isEmpty()) { while(node!=null) { stack.push(node); node = node.lchild; } if(stack!=null) { node = stack.pop(); System.out.print(node.data+" "); node = node.rchild; } } }
4、后序遍历
4.1 递归操作
//后序遍历,递归操作 public void postOrder(TreeNode root) { if(root==null) return ; postOrder(root.lchild); postOrder(root.rchild); System.out.print(root.data+" "); }
4.2 非递归操作
前提:设置标志结点pre,指示是否访问过某结点
思想:
* (1)若栈非空或者结点非空,则进入循环
* (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边
* (3)若栈非空,首先取出栈顶元素的右孩子赋给tmp
1、若栈顶元素的右孩子为空或者等于pre(即已访问过),则弹出元素并访问,将该结点赋值给pre,并将当前结点赋值为null
2、否则的话将右孩子赋值给当前结点
/* * 后序遍历,栈操作 * 前提:设置标志结点pre,指示是否访问过某结点 * 思想: * (1)若栈非空或者结点非空,则进入循环 * (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边 * (3)若栈非空,首先取出栈顶元素的右孩子赋给tmp * 1、若栈顶元素的右孩子为空或者等于pre(即已访问过),则弹出元素并访问,将该结点赋值给pre,并将当前结点赋值为null * 2、否则的话将右孩子赋值给当前结点 */ public void postOrder1() { Stackstack = new Stack<>(); TreeNode node = root,pre = root; while(!stack.isEmpty()||node!=null) { while(node!=null) { stack.push(node); node = node.lchild; } if(!stack.isEmpty()) { TreeNode tmp = stack.peek().rchild; if(tmp==null||tmp==pre) { node = stack.pop(); System.out.print(node.data+" "); pre = node; node = null; }else { node = tmp; } } } }
5、层次遍历(广度优先遍历)使用队列
思想:
* (1)读取根节点,并将其压入队列中
* (2)以队列的长度作为循环的判断条件,取出队收元素并访问,访问后将其弹出
* (3)判断是否有左右孩子,若有则加入队列中。
public void bfs() { Queuequeue = new LinkedList(); if(root==null) return ; queue.offer(root); while(queue.size()>0) { TreeNode node = queue.peek(); queue.poll(); System.out.print(node.data+" "); if(node.lchild!=null) { queue.offer(node.lchild); } if(node.rchild!=null) { queue.offer(node.rchild); } } }
6、深度优先遍历
此部分相对较难理解,自行琢磨
public void dfs(TreeNode node,List> nList,List
list) { if(node==null) return ; if(node.lchild==null&node.rchild==null) { list.add((Integer) node.data); nList.add(new ArrayList<>(list)); list.remove(list.size()-1); } list.add((Integer) node.data); dfs(node.lchild, nList, list); dfs(node.rchild, nList, list); list.remove(list.size()-1); }
7、求树的深度
(1)若二叉树为空,则返回0
(2)若二叉树非空,求左子树的深度,求右子树的深度
(3)比较左右子树的深度,求最大值加1,即为二叉树的深度
//求二叉树的深度 public int Depth(TreeNode node) { if(node==null) return 0; else { int ldepth = Depth(node.lchild); System.out.println("node'data:"+node.data+"ldepth: "+ldepth); int rdepth = Depth(node.rchild); System.out.println("node'data:"+node.data+"rdepth: "+rdepth+" "); if(ldepth<rdepth) return rdepth+1; else return ldepth+1; } }
7、应用及全部代码展示
1 package Main; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.Iterator; 6 import java.util.LinkedList; 7 import java.util.List; 8 import java.util.Queue; 9 import java.util.Scanner; 10 import java.util.Stack; 11 12 import javax.naming.directory.SearchControls; 13 public class Main{ 14 public static TreeNode root; 15 //建立二叉树内部类 16 class TreeNode{ 17 public Object data; //携带变量 18 public TreeNode lchild,rchild; //左右孩子 19 public TreeNode() { 20 data = null; 21 lchild = null; 22 rchild = null; 23 } 24 public TreeNode(Object data) { 25 this.data = data; 26 } 27 public void setLeft(TreeNode left) 28 { 29 this.lchild = left; 30 } 31 public void setRight(TreeNode right) 32 { 33 this.rchild = right; 34 } 35 } 36 //建立二叉树,通过List作为中间过渡量 37 public void CreatBinTree(int []datas,Listnodelist) { 38 for(int i=0;i ) 39 { 40 TreeNode aNode = new TreeNode(datas[i]); 41 nodelist.add(aNode); 42 } 43 //给所有父亲结点设定子节点 44 for(int index = 0;index ) 45 { 46 //在起始结点为0时,为N的父亲结点他的左孩子为2*N+1,右孩子为2*N+2 47 nodelist.get(index).lchild = nodelist.get(2*index+1); 48 nodelist.get(index).rchild = nodelist.get(2*index+2); 49 } 50 //单独处理最后一个父亲结点 51 int index = nodelist.size()/2-1; 52 nodelist.get(index).lchild = nodelist.get(2*index+1); 53 if(nodelist.size()%2==1) 54 nodelist.get(index).rchild = nodelist.get(2*index+2); 55 } 56 //先序遍历,递归操作 57 public void PreOrder(TreeNode root) 58 { 59 if(root == null) 60 return ; 61 System.out.print(root.data+" "); 62 PreOrder(root.lchild); 63 PreOrder(root.rchild); 64 } 65 /* 66 * 方法一:先序遍历,使用栈操作,相对较简单 67 * 思想: 68 * (1)若栈非空或者结点非空,则进入循环 69 * (2)若结点非空,读取该节点,并将结点压入栈中,结点向左孩子移动,移到最左孩子 70 * (3)若栈非空,取出栈顶元素,此时父节点已读,所以移向右孩子 71 * 核心为:边读取左结点变将其压入栈中,左孩子对下一级来说上也代表父亲结点,所以之后可以直接读取右孩子。 72 */ 73 public void preOrder1() 74 { 75 Stack stack = new Stack<>(); 76 TreeNode node = root; 77 while(!stack.isEmpty()||node!=null) 78 { 79 while(node!=null) 80 { 81 System.out.print(node.data+" "); //访问该节点 82 stack.push(node); 83 node = node.lchild; 84 } 85 if(!stack.isEmpty()) 86 { 87 node = stack.pop(); 88 node = node.rchild; 89 } 90 } 91 } 92 /* 93 * 方法二:先序遍历,使用栈操作,相对较麻烦 94 * 思想: 95 * (1)首先将根节点入栈 96 * (2)判断非空,将结点从栈中取出并访问 97 * (3)依次访问栈中的左孩子,并将右孩子放入栈中,结点不断往左孩子移动 98 * (4)重复步骤(2)(3),直到栈为空 99 */ 100 public void preOrder2() throws Exception 101 { 102 TreeNode pNode = root; 103 if(pNode!=null) //首先判断根结点是否为空 104 { 105 Stack astack = new Stack<>(); //构造栈操作 106 astack.push(pNode); //将根节点压入栈中 107 while(!astack.isEmpty()) //循环操作直到栈中没有结点存在,即最右结点访问完毕 108 { 109 pNode = astack.pop(); //首先将结点从栈中取出 110 System.out.print(pNode.data+" "); //访问该节点 111 while(pNode!=null) //若该结点不为空 112 { 113 if(pNode.lchild!=null) //访问左子树 114 System.out.print(pNode.lchild.data+" "); 115 if(pNode.rchild!=null) //将右子树压入栈中 116 astack.push(pNode.rchild); 117 pNode = pNode.lchild; //进入到下一个左子树中 118 } 119 } 120 121 } 122 } 123 //中序遍历,递归操作 124 public void inOrder(TreeNode root) 125 { 126 if(root==null) 127 return ; 128 inOrder(root.lchild); 129 System.out.print(root.data+" "); 130 inOrder(root.rchild); 131 } 132 /* 133 * 中序遍历,使用栈操作 134 * 思想: 135 * (1)若栈非空或者结点非空,则进入循环 136 * (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边 137 * (3)若栈非空,则取出栈顶元素,并读取访问数据,而后结点向右孩子移动 138 */ 139 public void inOrder1() throws Exception 140 { 141 TreeNode node = root; 142 Stack stack = new Stack<>(); 143 while(node!=null||!stack.isEmpty()) 144 { 145 while(node!=null) 146 { 147 stack.push(node); 148 node = node.lchild; 149 } 150 if(stack!=null) 151 { 152 node = stack.pop(); 153 System.out.print(node.data+" "); 154 node = node.rchild; 155 } 156 } 157 } 158 //后序遍历,递归操作 159 public void postOrder(TreeNode root) 160 { 161 if(root==null) 162 return ; 163 postOrder(root.lchild); 164 postOrder(root.rchild); 165 System.out.print(root.data+" "); 166 } 167 /* 168 * 后序遍历,栈操作 169 * 前提:设置标志结点pre,指示是否访问过某结点 170 * 思想: 171 * (1)若栈非空或者结点非空,则进入循环 172 * (2)若结点非空,则将结点压入栈中,结点向左孩子移动,一直到最左边 173 * (3)若栈非空,首先取出栈顶元素的右孩子赋给tmp 174 * 1、若栈顶元素的右孩子为空或者等于pre(即已访问过),则弹出元素并访问,将该结点赋值给pre,并将当前结点赋值为null 175 * 2、否则的话将右孩子赋值给当前结点 176 */ 177 public void postOrder1() 178 { 179 Stack stack = new Stack<>(); 180 TreeNode node = root,pre = root; 181 while(!stack.isEmpty()||node!=null) 182 { 183 while(node!=null) 184 { 185 stack.push(node); 186 node = node.lchild; 187 } 188 if(!stack.isEmpty()) 189 { 190 TreeNode tmp = stack.peek().rchild; 191 if(tmp==null||tmp==pre) 192 { 193 node = stack.pop(); 194 System.out.print(node.data+" "); 195 pre = node; 196 node = null; 197 }else { 198 node = tmp; 199 } 200 201 } 202 } 203 204 } 205 /*层次遍历,即广度优先遍历,从上到下遍历二叉树 206 * 思想: 207 * (1)读取根节点,并将其压入队列中 208 * (2)以队列的长度作为循环的判断条件,取出队收元素并访问,访问后将其弹出 209 * (3)判断是否有左右孩子,若有则加入队列中。 210 * */ 211 public void bfs() 212 { 213 Queue queue = new LinkedList(); 214 if(root==null) 215 return ; 216 queue.offer(root); 217 while(queue.size()>0) { 218 TreeNode node = queue.peek(); 219 queue.poll(); 220 System.out.print(node.data+" "); 221 if(node.lchild!=null) 222 { 223 queue.offer(node.lchild); 224 } 225 if(node.rchild!=null) 226 { 227 queue.offer(node.rchild); 228 } 229 } 230 231 } 232 /* 233 * 深度优先遍历,从左到右遍历二叉树 234 * */ 235 public void dfs(TreeNode node,List > nList,List
list) 236 { 237 if(node==null) 238 return ; 239 if(node.lchild==null&node.rchild==null) 240 { 241 list.add((Integer) node.data); 242 nList.add(new ArrayList<>(list)); 243 list.remove(list.size()-1); 244 } 245 list.add((Integer) node.data); 246 dfs(node.lchild, nList, list); 247 dfs(node.rchild, nList, list); 248 list.remove(list.size()-1); 249 } 250 //查找算法 251 public static TreeNode Searchparameter(TreeNode root,int x) 252 { 253 TreeNode node = root; 254 if(root==null) 255 return null; 256 else { 257 if(node.data.equals(x)) 258 return node; 259 else { 260 TreeNode aNode = Searchparameter(node.lchild, x); 261 if(aNode==null) 262 return Searchparameter(node.rchild, x); 263 else 264 return aNode; 265 } 266 } 267 } 268 //求二叉树的深度 269 public int Depth(TreeNode node) 270 { 271 if(node==null) 272 return 0; 273 else { 274 int ldepth = Depth(node.lchild); 275 int rdepth = Depth(node.rchild); 276 if(ldepth<rdepth) 277 return rdepth+1; 278 else 279 return ldepth+1; 280 } 281 } 282 public static void main(String[] args) throws Exception { 283 int datas[] = {1,2,3,4,5,6,7,8,9,10}; 284 List nodelist = new LinkedList<>(); 285 Main aMain = new Main(); 286 aMain.CreatBinTree(datas,nodelist); 287 root = nodelist.get(0); 288 289 System.out.println("First order traversal(recursive):"); 290 aMain.PreOrder(root); 291 System.out.println(); 292 System.out.println("First order traversal(stack--1):"); 293 aMain.preOrder1(); 294 System.out.println(); 295 System.out.println("First order traversal(stack--2):"); 296 aMain.preOrder2(); 297 System.out.println(); 298 System.out.println("Inorder traversal(recursive):"); 299 aMain.inOrder(root); 300 System.out.println(); 301 System.out.println("Inorder traversal(stack--1):"); 302 aMain.inOrder1(); 303 System.out.println(); 304 System.out.println("Postorder traversal(recursive):"); 305 aMain.postOrder(root); 306 System.out.println(); 307 System.out.println("Postorder traversal(stack--1):"); 308 aMain.postOrder1(); 309 System.out.println(); 310 System.out.println("Level traversal(queue--1):"); 311 aMain.bfs(); 312 313 List > rst = new ArrayList<>(); 314 List
list = new ArrayList<>(); 315 System.out.println(); 316 System.out.println("Depth first traversal(queue--1):"); 317 aMain.dfs(root,rst,list); 318 System.out.println(rst); 319 int x = 6; 320 TreeNode aNode = Searchparameter(root,x); 321 System.out.println(aNode.data); 322 323 int depth = aMain.Depth(root); 324 System.out.println("the depth of the tree is :"+depth); 325 } 326 327 328 }
结果展示: