闵老板の帖子: 日撸 Java 三百行(21-30天,树与二叉树)


1. 二叉树的深度遍历的递归实现

树是数据结构中的重中之重, 特别是二叉树.许多实际问题抽象出来的数据结构往往是二叉树形式, 即使是一般的树也能简单地转换为二叉树, 而且二叉树的存储结构及其算法都较为简单, 因此二叉树显得特别重要. 二叉树特点是每个结点最多只能有两棵子树, 且有左右之分.

这里用递归的方法为二叉树写了几个方法:

1. 遍历. 包括前序, 中序, 后序遍历.

2. 计算深度的方法.

3. 计算总结点数的方法.

package datastructure.tree;public class BinaryTree {// The value;char value;// The left child;BinaryTree leftChild;// The right child;BinaryTree rightChild;/*** ********************* Construct a tree-node.** @param paraValue The value you given.*********************/public BinaryTree(char paraValue) {value = paraValue;leftChild = null;rightChild = null;}// Of one constructor/*** ********************* Construct a tree with 7 nodes.** @return The tree.*********************/public static BinaryTree manualConstructTree() {// The root of the tree.BinaryTree resultTree = new BinaryTree('A');// The other nodes.BinaryTree tempTreeB = new BinaryTree('B');BinaryTree tempTreeC = new BinaryTree('C');BinaryTree tempTreeD = new BinaryTree('D');BinaryTree tempTreeE = new BinaryTree('E');BinaryTree tempTreeF = new BinaryTree('F');BinaryTree tempTreeG = new BinaryTree('G');// Link them.resultTree.leftChild = tempTreeB;resultTree.rightChild = tempTreeC;tempTreeB.rightChild = tempTreeD;tempTreeC.leftChild = tempTreeE;tempTreeD.leftChild = tempTreeF;tempTreeD.rightChild = tempTreeG;return resultTree;}// Of manualConstrucTree/*** ********************* Pre-Order.*********************/public void preOrder() {System.out.print(value + " ");if(leftChild != null) {leftChild.preOrder();}// Of ifif(rightChild != null) {rightChild.preOrder();}// Of if}// Of preOrder/*** ********************* In-Order.*********************/public void inOrder() {if(leftChild != null) {leftChild.inOrder();}// Of ifSystem.out.print(value + " ");if(rightChild != null) {rightChild.inOrder();}// Of if}// Of inOrder./*** ********************* Post-Order.*********************/public void postOrder() {if(leftChild != null) {leftChild.postOrder();}// Of ifif(rightChild != null) {rightChild.postOrder();}// Of ifSystem.out.print(value + " ");}// Of postOrder./*** ********************* Calculate the depth of the tree.** @return The depth.*********************/public int getDepth() {if(leftChild == null && rightChild == null) {return 1;}// Of if int tempLeftDepth = 0, tempRightDepth = 0;if(leftChild != null) {tempLeftDepth = leftChild.getDepth();}// Of ifif(rightChild != null) {tempRightDepth = rightChild.getDepth();}// Of ifif(tempLeftDepth >= tempRightDepth) {return tempLeftDepth+1;}// Of if else{return tempRightDepth+1;}// Of else}// Of getDepth/*** ********************* Calculate all nodes.** @return The nodes of the tree.*********************/public int getNumNodes() {if ((leftChild == null) && (rightChild == null)) {return 1;} // Of ifint tempLeftNodes = 0, tempRightNodes = 0;if (leftChild != null) {tempLeftNodes = leftChild.getNumNodes();} // Of ifif (rightChild != null) {tempRightNodes = rightChild.getNumNodes();} // Of ifreturn tempLeftNodes + tempRightNodes + 1;}// Of getNumNodes./************************ The entrance of the program.* * @param args Not used now.**********************/public static void main(String args[]) {BinaryTree tempTree = manualConstructTree();System.out.println("Pre-order visit:");tempTree.preOrder();System.out.println("\rIn-order visit:");tempTree.inOrder();System.out.println("\rPost-order visit:");tempTree.postOrder();System.out.println("\rThe depth is: " + tempTree.getDepth());System.out.println("The number of nodes is: " + tempTree.getNumNodes());}// Of main}// Of BinaryCharTree

输出:

Pre-order visit:
A B D F G C E
In-order visit:
B F D G A E C
Post-order visit:
F G D B E C A
The depth is: 4
The number of nodes is: 7

2. 二叉树的存储

我们可以完全满二叉树的角度广度优先遍历的角度来考虑这个问题: 每个节点都有一个 name 及其在二叉树中的位置. 令根节点的位置为 0; 则第 2 层节点的位置依次为 1 至 2; 第 3 层节点的位置依次为 3 至 6. 以此类推.

把昨天那个例子所对应的二叉树画出来, 我们有两种方法:

1.空使用 0 来表示, 可以用一个向量来存储:
        [A, B, C, 0, D, E, 0, 0, 0, F, G]
        优点: 仅需要一个向量, 简单直接.
        缺点: 对于实际的二叉树, 很多子树为空, 导致大量的 0 值.
     2.使用压缩存储方式, 即将节点的位置和值均存储. 可表示为两个向量:
        [0, 1, 2, 4, 5, 9, 10]
        [A, B, C, D, E,F, G]

我们用队列的方式来定义. 与之前不同的是, 这次定义用的是Object类型, 它可以接收任意类型的数据.

package datastructure;public class CircularObjectQueue {// The total space. But the actual sapce will be one less.public static final int MAX_SIZE = 10;// The data;Object[] data;// The index of the head.int front;// The index of the tail.int rear;/*** ********************* The constructor.*********************/public CircularObjectQueue() {data = new Object[MAX_SIZE];front = 0;rear = 0;}// Of the constructor/*** ********************* Enqueue.** @param paraValue The given value.* @return true or false.*********************/public boolean enqueue(Object paraValue) {if(front == (rear + 1) % MAX_SIZE) {// System.out.println("Queue full");return false;}data[rear % MAX_SIZE] = paraValue;rear++;return true;}// Of enqueue/*** ********************* Dequeue.** @return The dequeued value.*********************/public Object dequeue() {Object resultValue;if(front == rear) {// System.out.println("The queue is empty, dequeue fail");return null;}// Of ifresultValue = data[front % MAX_SIZE];front++;return resultValue;}// Of dequeue/*** ********************** Output the values of all member variables, and separated by comma.** @return A new string.**********************/public String toString() {String resultString = "";if(front == rear) {return "empty";}// Of iffor(int i = front; i < rear - 1; i++) {resultString += data[i % MAX_SIZE] + ", ";}// Of for i resultString += data[(rear-1) % MAX_SIZE];return resultString;}// Of toString
}// Of class CircularObjectQueue

下面是老师的代码实现. 将内容位置应在之前写的BinaryTree.java中.

需要注意的是,节点的索引从0开始. 那么节点的左孩子的索引是其索引的二倍+1, 右孩子是其索引的二倍+2.

 /*** The values of nodes according to breadth first traversal.*/char[] valuesArray;/*** The indices in the complete binary tree.*/int[] indicesArray;/*********************** Convert the tree to data arrays, including a char array and an int array.* The results are stored in two member variables.* * @see #valuesArray* @see #indicesArray**********************/public void toDataArrays() {//Initialize arrays.int tempLength = getNumNodes();valuesArray = new char[tempLength];indicesArray = new int[tempLength];int i = 0;//Traverse and convert at the same time.CircleObjectQueue tempQueue = new CircleObjectQueue();tempQueue.enqueue(this);CircleIntQueue tempIntQueue = new CircleIntQueue();tempIntQueue.enqueue(0);BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();int tempIndex = tempIntQueue.dequeue();while (tempTree != null) {valuesArray[i] = tempTree.value;indicesArray[i] = tempIndex;i++;if (tempTree.leftChild != null) {tempQueue.enqueue(tempTree.leftChild);tempIntQueue.enqueue(tempIndex * 2 + 1);} // Of ifif (tempTree.rightChild != null) {tempQueue.enqueue(tempTree.rightChild);tempIntQueue.enqueue(tempIndex * 2 + 2);} // Of iftempTree = (BinaryCharTree) tempQueue.dequeue();tempIndex = tempIntQueue.dequeue();} // Of while}// Of toDataArrays/************************ The entrance of the program.* * @param args*            Not used now.**********************/public static void main(String args[]) {BinaryCharTree tempTree = manualConstructTree();System.out.println("\r\nPreorder visit:");tempTree.preOrderVisit();System.out.println("\r\nIn-order visit:");tempTree.inOrderVisit();System.out.println("\r\nPost-order visit:");tempTree.postOrderVisit();System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());System.out.println("The number of nodes is: " + tempTree.getNumNodes());tempTree.toDataArrays();System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));}// Of main

输出:

Preorder visit:
A B D F G C E
In-order visit:
B F D G A E C
Post-order visit:
F G D B E C A
The depth is: 4
The number of nodes is: 7
The values are: [A, B, C, D, E, F, G]
The indices are: [0, 1, 2, 4, 5, 9, 10]

3. 使用具有通用性的队列

我们刚刚已经知道, Object可以用来接收任意类型数据, 那么我们在定义队列的时候, 也不再需要专门去为不同的数据类型创建不同的队列了.

我们可以直接这样定义数据:

Object[] data;

但是在使用的时候, 需要利用强制类型转换使其变成本身的类别. 比如

tempTree = (BinaryCharTree) tempQueue.dequeue();

4. 二叉树的建立

这里是二叉树的另一种构造方法, 通过输入相应的valuesArray、indicesArray来构造.

主要有三个步骤:

1. 创建一个Binary类型的数组来存储我们需要的所有节点.

2. 采用双重循环的方式判断是否为某个节点的左右孩子. 这里设计的十分巧妙, 从除根节点外的第一个节点出发, 判断其与之前的节点是否满足为其左右孩子的条件, 若满足条件, 则用之前创建好的Binary类型节点链接起来, 然后跳出循环, 判断下一个节点, 以此直到所有节点判断完毕.

3. 链接完毕, 回到根节点.

/************************ The second constructor. The parameters must be correct since no validity* check is undertaken.* * @param paraDataArray    The array for data.* @param paraIndicesArray The array for indices.**********************/public BinaryTree(char[] paraValuesArray, int[] paraIndicesArray) {// Step 1. Use a sequential list to store all nodes.int tempNumNodes = paraValuesArray.length;BinaryTree[] tempAllNodes = new BinaryTree[tempNumNodes];for (int i = 0; i < tempNumNodes; i++) {tempAllNodes[i] = new BinaryTree(paraValuesArray[i]);} // Of for i// Step 2. Link these nodes.for (int i = 1; i < tempNumNodes; i++) {for (int j = 0; j < i; j++) {System.out.println("indices " + paraIndicesArray[j] + " vs. " + paraIndicesArray[i]);if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 1) {tempAllNodes[j].leftChild = tempAllNodes[i];System.out.println("Linking " + j + " with " + i);break;} else if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 2) {tempAllNodes[j].rightChild = tempAllNodes[i];System.out.println("Linking " + j + " with " + i);break;} // Of if} // Of for j} // Of for i//Step 3. The root is the first node.value = tempAllNodes[0].value;leftChild = tempAllNodes[0].leftChild;rightChild = tempAllNodes[0].rightChild;}// Of the the third constructor

5. 二叉树深度遍历的栈实现 (中序)

5.1 构建通用栈

在之前写的stack.java中稍作修改, 并添加了.isEmpty()方法.

package datastructure.Stack;public class ObjectStack {// The max depth of the stack.public static final int MAX_DEPTH = 10;// The actual depth of the stack.int depth;// The data.Object[] data;/*** ********************** Initialize an empty stack.**********************/public ObjectStack() {depth = 0;data = new Object[MAX_DEPTH];}// Of the constructor/*** ********************** Push a value into the stack. If the stack is full, push fail.* * @param tempNode The given value.* @return true or false.**********************/public boolean push(Object paraObject) {if (depth == MAX_DEPTH) {System.out.println("The stack is full, push fail");return false;} // Of ifdata[depth] = paraObject;depth++;return true;}// Of push/*** ********************** Pop the value at the of top of stack. If the stack is empty, pop fail.** @return The value at the of top of stack.**********************/public Object pop() {if (depth == 0) {System.out.println("The stack is empty, pop fail");return '\0';} // Of ifObject resultValue = data[depth - 1];depth--;return resultValue;}// Of pop/*** ********************** Output the values of all member variables.** @return A new string.**********************/public String toString() {String resultString = "";if (depth == 0) {return "empty";} // Of iffor (int i = 0; i < depth; i++) {resultString += data[i];} // Of for ireturn resultString;}// Of toString/*** ********************* Determine whether the stack is empty. True for empty.** @return true or false.*********************/public boolean isEmpty() {if(depth == 0) {return true;}// Of ifreturn false;}// Of isEmpty}// Of class ObjectStack

5.2 中序遍历

简单来说, 入左, 左空出左,入右...

    /************************ In-order with stack.**********************/public void inOrderWithStack() {ObjectStack tempStack = new ObjectStack();BinaryTree tempNode = this;while (! tempStack.isEmpty() || tempNode != null) {if (tempNode != null) {tempStack.push(tempNode);tempNode = tempNode.leftChild;} else {tempNode = (BinaryTree) tempStack.pop();System.out.print(tempNode.value + " ");tempNode = tempNode.rightChild;} // Of if} // Of while}// Of inOrderWithStack

6. 小结

看不懂就反复看, 或者画图画出来, 多敲几遍, 然后自己琢磨.

Java学习(21-25天, 树与二叉树)相关推荐

  1. 数据结构学习笔记(5.树与二叉树 6.图)

    文章目录 第五章 树与二叉树 树 树的常考性质 二叉树--定义.基本术语 二叉树--常考性质 二叉树--存储结构 二叉树--先序.中序.后序遍历 二叉树--层序遍历 由遍历序列构造二叉树 线索二叉树- ...

  2. java学习(25):三目运算符

    /任务4:三目运算符 编写控制台java程序, 使用Scanner对象相关方法从控制台接收两个整数,比较他们的大小/ import java.util.Scanner; public class te ...

  3. Java学习笔记25

    Collection和Map接口是集合框架的根接口,List为Collection接口的子接口,List集合代表一个元素有序.可重复的集 合,集合中每个元素都有其对应的顺序索引.List集合允许使用重 ...

  4. 数据结构与算法——从零开始学习(五)树和二叉树

    系列文章 第一章:基础知识 第二章:线性表 第三章:栈和队列 第四章:字符串和数组

  5. 【图解数据结构】树和二叉树全面总结(上)

    目录 一.前言 二.树的概念和定义 三.二叉树 1.基本概念 2.基本形态 3.性质 4.满二叉树 5.完全二叉树 四.存储结构 1.顺序存储 2.二叉链表 3.三叉链表 一.前言 学习目标:理解树和 ...

  6. 成为Java高手的25个学习要点

    成为Java高手的25个学习要点 想要精通Java,成为Java高手,需要不断的学习和积累.本文给出了Java学习过程中需要注意的25个学习目标,希望可以给您带来帮助. AD: 2013大数据全球技术 ...

  7. 想要成为JAVA高手的25个学习目标

    本文将告诉你学习Java需要达到的25个目标,希望能够对你的学习及找工作有所帮助.对比一下自己,你已经掌握了这25条中的多少条了呢? 1.你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GO ...

  8. Java开发 - 树(二叉树,二叉排序树,红黑树)

    目录 前言 你好,认识一下,我是树 二叉树与二叉排序树 二叉排序树特点 为什么说二叉排序树查询效率要高于链表呢? 元素的类型 比较器 手写二叉排序树 定义一棵二叉树 增加元素 查询元素 修改元素 删除 ...

  9. 树梅派学习 21. 串口连接

    树梅派学习 21. 串口连接 接线: 其中6.8.10 是串口的引脚. 1. 执行命令 sudo apt-get update sudo apt-get upgrade sudo reboot 2. ...

  10. 树、二叉树、AVL树,B树基础学习

    树.二叉树.AVL树,B树基础学习 一.树的基本概念 树是一种数据结构,它是由n(n>1)个有限节点组成的一个具有层次关系的集合. 树的基本概念 1.双亲:若有一个结点有子树,那么该结点就称为子 ...

最新文章

  1. LSGO:祝大家新年快乐!
  2. python模块讲解_python模块详解 | filecmp
  3. PHP的表单获取与HHTP请求方式
  4. 使java代码更干净_java如何使用Lombok更优雅地编码
  5. 做项目时的几个感慨(持续更新...)
  6. CSS中的box-sizing
  7. 为了减少接口的响应时间,有哪些优化措施?(可以从架构、代码等各个角度谈)?
  8. 京东健康股价创下新高 市值突破6000亿港元
  9. mysql国内源码安装,mysql 源码包安装
  10. 今日力推: Android 厨客APP / Android 趣刻App
  11. 耐驰测试仪上的软件,Proteus
  12. 解决FreeMind启动不成功,显示This application requires a Java Runtime Environment 1.5.0
  13. mac php71 php fpm,Mac PHP-fpm
  14. cd linux 镜像,cdlinux镜像 v0.9.7官方版
  15. JavaScript-ES6新特性详解
  16. Unity插件 - MeshEditor(五) 网格顶点动画(变形动画)
  17. 导数的零点定理与达布定理
  18. 增量式编码器和绝对式编码器,ABI信号和UVW信号、编码器PWM信号
  19. 智能家居的应用研究现状
  20. python创建类的两个对象_Python为一个类创建多个对象

热门文章

  1. 跟据URL来实现WebService
  2. Hawkeye - The .Net Runtime Object Editor
  3. 大规模图搜索和实时计算在阿里反作弊系统中的应用
  4. 第三季-第3课-Coredump程序故障分析
  5. 【BZOJ 3172】单词
  6. 基于VS快速排序的单元测试
  7. ECJia 到家 v1.5.1 发布,基于 O2O 的移动电商开源系统
  8. 图片水印工具类java
  9. String类的编码和解码问题
  10. WINDOWS下简单操作SQLITE3