java 二叉树的深度 非递归算法_数据结构5_java---二叉树,树的建立,树的先序、中序、后序遍历(递归和非递归算法),层次遍历(广度优先遍历),深度优先遍历,树的深度(递归算法)...

本文详细介绍了如何使用Java实现二叉树的非递归遍历,包括先序、中序、后序以及层次遍历,并提供了相关代码示例。此外,还讲解了如何计算二叉树的深度,帮助读者深入理解数据结构中的树操作。
摘要由CSDN通过智能技术生成

1、二叉树的建立

首先,定义数组存储树的data,然后使用list集合将所有的二叉树结点都包含进去,最后给每个父亲结点赋予左右孩子。

需要注意的是:最后一个父亲结点需要单独处理

1 public staticTreeNode root;2 //建立二叉树内部类

3 classTreeNode{4 public Object data; //携带变量

5 public TreeNode lchild,rchild; //左右孩子

6 publicTreeNode() {7 data = null;8 lchild = null;9 rchild = null;10 }11 publicTreeNode(Object data) {12 this.data =data;13 }14 public voidsetLeft(TreeNode left)15 {16 this.lchild =left;17 }18 public voidsetRight(TreeNode right)19 {20 this.rchild =right;21 }22 }23 //建立二叉树,通过List作为中间过渡量

24 public void CreatBinTree(int []datas,Listnodelist) {25 for(int i=0;i

31 for(int index = 0;index

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 voidPreOrder(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 voidpreOrder1()

{

Stack stack = 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() throwsException

{

TreeNode pNode=root;if(pNode!=null) //首先判断根结点是否为空

{

Stack astack = 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 voidinOrder(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() throwsException

{

TreeNode node=root;

Stack stack = 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 voidpostOrder(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 voidpostOrder1()

{

Stack stack = 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 voidbfs()

{

Queue queue = newLinkedList();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,Listlist)

{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 intDepth(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

return ldepth+1;

}

}

7、应用及全部代码展示

1 packageMain;2

3 importjava.util.ArrayList;4 importjava.util.Collection;5 importjava.util.Iterator;6 importjava.util.LinkedList;7 importjava.util.List;8 importjava.util.Queue;9 importjava.util.Scanner;10 importjava.util.Stack;11

12 importjavax.naming.directory.SearchControls;13 public classMain{14 public staticTreeNode root;15 //建立二叉树内部类

16 classTreeNode{17 public Object data; //携带变量

18 public TreeNode lchild,rchild; //左右孩子

19 publicTreeNode() {20 data = null;21 lchild = null;22 rchild = null;23 }24 publicTreeNode(Object data) {25 this.data =data;26 }27 public voidsetLeft(TreeNode left)28 {29 this.lchild =left;30 }31 public voidsetRight(TreeNode right)32 {33 this.rchild =right;34 }35 }36 //建立二叉树,通过List作为中间过渡量

37 public void CreatBinTree(int []datas,Listnodelist) {38 for(int i=0;i

44 for(int index = 0;index

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 voidPreOrder(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 voidpreOrder1()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() throwsException101 {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 voidinOrder(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() throwsException140 {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 voidpostOrder(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)若栈非空,首先取出栈顶元素的右孩子赋给tmp174 * 1、若栈顶元素的右孩子为空或者等于pre(即已访问过),则弹出元素并访问,将该结点赋值给pre,并将当前结点赋值为null175 * 2、否则的话将右孩子赋值给当前结点176 */

177 public voidpostOrder1()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 voidbfs()212 {213 Queue queue = newLinkedList();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,Listlist)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,intx)252 {253 TreeNode node =root;254 if(root==null)255 return null;256 else{257 if(node.data.equals(x))258 returnnode;259 else{260 TreeNode aNode =Searchparameter(node.lchild, x);261 if(aNode==null)262 returnSearchparameter(node.rchild, x);263 else

264 returnaNode;265 }266 }267 }268 //求二叉树的深度

269 public intDepth(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

279 return ldepth+1;280 }281 }282 public static void main(String[] args) throwsException {283 int datas[] = {1,2,3,4,5,6,7,8,9,10};284 List nodelist = new LinkedList<>();285 Main aMain = newMain();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 }

结果展示:

33bcf87452e7349fc16fb53a865427a7.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值