树形结构是一种重要的非线性结构。其中,二叉树是我们学习中的重点中的重点——因为任何一颗树通过一定的变换都能变成二叉树。每颗树都只有一个根节点。n(n>=2)棵树可以形成森林。同样,森林可以转化成普通的树,而普通的树也可以转化成森林,更可以转化成二叉树。这就对我们很有利了。因为,我们只要把大部分的时间来研究二叉树就行了。
二叉树是每个节点至多有两颗子树的树(即二叉树不存在度大于2的节点)。而且,二叉树有严格的左右之分,不能随意互换。二叉树有很多的性质。比如说,在一颗树的第i层上至多有2^(i-1)个节点(根算作第0层)。深度为k的二叉树最多有2^k-1个节点(k>1)。对于任何一棵二叉树,如果其终端节点数为n0,度的节点数为n2,则n0 = n2 + 1。同时,具有n个节点的完全二叉树的深度为[logn/log2]+1个。
二叉树也有很多的存储结构,比如说顺序存储结构(仅仅使用于完全二叉树)、链式存储结构(可分为两种,一种是有存储数据域、左孩子的指针域、右孩子的指针域,所得二叉树成为二叉链表,另一种除了有存储数据域、左孩子的指针域、右孩子的指针域,还有指向双亲的指针域。
二叉树的遍历是一个重点。在Java中,我们依旧可以采用先序遍历(即先遍历根,再遍历左孩子,再右孩子)、中序遍历(即先遍历左孩子,再遍历根,最后遍历右孩子)、后序遍历(即先遍历左孩子,再遍历右孩子,最后遍历根),还有一种最容易理解的层次遍历。
实现一个遍历,既可以用递归的方法,也可以用非递归的方法。递归容易理解,而非递归则在空间利用率上有优势。
通过中序遍历和先序遍历或者是中序遍历和后序遍历,我们可以完全确定出一棵二叉树。
二叉树中有最优二叉树(赫夫曼树),带权路径长度最小的二叉树便称作最优二叉树或者赫夫曼树。赫夫曼树在计算图像压缩处理、数据压缩等方面有着很大的用途。
学好树,能够为我们提供一些新的解决问题的思路,因此十分重要。
下面提供一段对于存储在二叉树的固定表达式的求解。由于时间仓促,还没来得及写将普通的表达式中缀式转换为普通的二叉树(不含括号),我会慢慢完善的。将这个树完善为一个通用的能计算表达式的二叉树。
现行的表达式为:2+10*5-20/2
要计算这个表达式,我用了数据结构中的栈,用来储存数。
分为四个类:树的节点类、主函数类、栈接口类、栈接口实现类。
树的节点类
public class TreeNode {
//定义数据域
private Object obj;
//指向左孩子
private TreeNode lChild;
//定义右孩子
private TreeNode rChild;
//传入要构造的数据
public TreeNode(Object obj){
this.obj = obj;
}
//修改数据域
public void setObj(Object obj){
this.obj = obj;
}
//得到数据
public Object getObj(){
return obj;
}
//设置左孩子
public void setLChild(TreeNode lChild){
this.lChild = lChild;
}
//得到左孩子
public TreeNode getLChild(){
return lChild;
}
//设置右孩子
public void setRChild(TreeNode rChild){
this.rChild = rChild;
}
//得到右孩子
public TreeNode getRChild(){
return rChild;
}
}
主函数类。说实话,这里写的并不是那么好。一方面没有实现中缀表达式转化为二叉树,而采用了直接创立树的节点的方法;另一方面违背了面向对象的思想,一团乱麻。
public class BTreeTest {
private static TreeNode root;
private static Stack OPND = new Stack();
public static void main(String[] args) {
BTreeTest test = new BTreeTest();
test.buildBTree();
test.midOrder(root);
test.posOrder(root);
if (OPND.lengthGet() == 1) {
System.out.println("=" + OPND.delete());
}
}
/**
* 建立二叉树
*/
private void buildBTree() {
TreeNode node1 = new TreeNode('-');
TreeNode node2 = new TreeNode('+');
TreeNode node3 = new TreeNode('/');
TreeNode node4 = new TreeNode(2);
TreeNode node5 = new TreeNode('*');
TreeNode node6 = new TreeNode(20);
TreeNode node7 = new TreeNode(2);
TreeNode node8 = new TreeNode(10);
TreeNode node9 = new TreeNode(5);
root = node1;
node1.setLChild(node2);
node1.setRChild(node3);
node2.setLChild(node4);
node2.setRChild(node5);
node3.setLChild(node6);
node3.setRChild(node7);
node5.setLChild(node8);
node5.setRChild(node9);
}
/**
* 中序遍历二叉树,得到输入的表达式
*/
public void midOrder(TreeNode root){
//root为空,则自然地跳出这次递归;root不为空,则继续递归
if(root != null){
midOrder(root.getLChild());
System.out.print(root.getObj());
midOrder(root.getRChild());
}
}
/**
* 后序遍历二叉树,得到逆波兰式,同时用栈计算出值
* @param root根
*/
public void posOrder(TreeNode root) {
int a,b;
if (root != null) {
posOrder(root.getLChild());
posOrder(root.getRChild());
//判断是加法还是减法,还是操作数
if (root.getObj().equals('+')) {
OPND.add(OPND.delete() + OPND.delete());
} else if (root.getObj().equals('-')) {
//因为减法和除法的两个操作数有先后顺序,所以不能够将操作数按取出的顺序操作,而应该相反
a = OPND.delete();
b = OPND.delete();
OPND.add((b-a));
} else if (root.getObj().equals('*')) {
OPND.add(OPND.delete() * OPND.delete());
} else if (root.getObj().equals('/')) {
a = OPND.delete();
b = OPND.delete();
OPND.add((b/a));
} else {
// 这样能够保留Object这个通用接口,成功地将Object类中的int转换成整数
int num = Integer.parseInt(root.getObj().toString());
OPND.add(num);
}
}
}
}
栈接口
package LinkBinaryTree2;
public interface StackInterface {
//往栈中添加一个元素
void add(int e);
//删除一个元素
int delete();
//判断栈是否为空
boolean isEmpty();
//求得栈的长度
int lengthGet();
//清空栈
void initStack();
}
栈的实现:由于知识有限,没有设计成为泛型也是遗憾吧
import java.util.Arrays;
public class Stack implements StackInterface {
/**
* 往栈中添加一个元素
*/
public void add(int e) {
int[] temp = new int[++topOfStack];
temp = Arrays.copyOf(stack, topOfStack);
temp[topOfStack - 1] = e;
stack = temp;
}
/**
* 删除一个元素
*/
public int delete() {
int reElem = (int) stack[topOfStack - 1];
topOfStack--;
return reElem;
}
/**
* 判断栈是否为空
*/
public boolean isEmpty() {
if (topOfStack == 0)
return true;
else
return false;
}
/**
* 获得栈的长度
*/
public int lengthGet() {
return topOfStack;
}
/**
* 清空栈
*/
public void initStack() {
topOfStack = 0;
}
private int[] stack = new int[0];
private int topOfStack=0;
}
分享到:
相关推荐
1. 层次遍历法:二叉树转换为树的方法之一是通过层次遍历(Level Order Traversal)。在层次遍历过程中,将同一层的节点视为兄弟节点,这样可以恢复树的结构。这种方法适用于完全二叉树,但对于非完全二叉树,可能...
性质1指出,树中的结点总数等于所有结点的度数之和再加1。性质2说明,在度为m的树中,第i层最多有mi-1个结点。这些性质在分析和操作树结构时具有指导意义。 二叉树是树的一个特例,每个节点最多有两个子节点,分为...
树和二叉树是计算机科学中数据结构的重要组成部分,它们在算法设计、文件系统、编译原理、图形处理等多个领域有着广泛的应用。本课件详细介绍了树与二叉树的相关概念,旨在帮助学习者深入理解并掌握这些知识。 首先...
树与二叉树的主要区别在于,树的子树之间没有顺序关系,而二叉树中的每个节点有明确的左子树和右子树之分,这使得二叉树在表示某些特定的关系时更为有序。例如,在二叉搜索树中,左子树的值总是小于父节点,右子树的...
### 数据结构之树和二叉树实验报告知识点详解 #### 实验目的 1. **掌握二叉树的结构特征**: - 了解二叉树的基本定义:每个节点最多有两个子节点的树形结构。 - 理解二叉树的特性,如满二叉树、完全二叉树等概念...
在计算机科学领域,树和二叉树是两种重要的数据结构,它们在许多应用中发挥着核心作用,如文件系统、数据库索引、编译器设计等。本篇将深入探讨这些概念及其相关的算法。 首先,我们要理解“树”这一概念。树是一种...
二叉树是树的一种特殊形式,每个节点最多只有两个子节点,通常分为左子节点和右子节点。树与二叉树之间的转化是一个重要的概念,尤其是在数据结构和算法的学习中。下面我们将详细探讨这个主题,同时也会涉及树的遍历...
树和二叉树-层序遍历二叉树 在计算机科学中,树和二叉树是很重要的数据结构概念。我们可以使用链表来存储二叉树,并使用层序遍历算法来遍历它。层序遍历二叉树的算法可以分为三步:首先,建立二叉树的链表存储结构...
"树与二叉树算法汇总" 本资源摘要信息主要讨论树与二叉树算法,涵盖树与二叉树的表示、遍历和操作等方面的知识点。 一、树与二叉树的表示 树是一种基本的数据结构,用于存储具有层次关系的数据。二叉树是树的一种...
树与二叉树算法总结 树与二叉树是计算机科学中非常重要的一部分,掌握树与二叉树的算法对于数据结构和算法设计非常重要。本文将对树与二叉树的基本概念、性质、运算和应用进行总结。 一、树的基本概念 树是一种非...
"树和二叉树的使用" 树是一种非常重要的数据结构,广泛应用于计算机科学和信息技术领域。树的类型定义、存储结构、遍历和应用都是计算机科学和信息技术的重要组成部分。本文将详细介绍树的类型定义、二叉树的存储...
本次课程设计的主题是“二叉树的遍历及树与二叉树的转换”,这涉及到两个核心概念:二叉树的遍历方法和树与二叉树之间的转化。 首先,我们来深入理解二叉树的遍历。二叉树是由节点构成的数据结构,每个节点最多有两...
"二叉树面试题 树和二叉树总结" 本资源摘要信息涵盖了树和二叉树的面试题总结,包括选择题和解释。涵盖的知识点包括树和二叉树的定义、性质、操作和应用等。 一、树和二叉树的定义 树是一种数据结构,由一个根...
"树和二叉树" 树和二叉树是计算机科学中的一类重要的数据结构,它们广泛应用于编译程序、数据库系统、算法分析等领域。 树的定义和基本概念: 树是 n(n>=0) 个结点的有限集 T,T 为空时称为空树,否则它满足两个...
二叉树的性质是本章的重点之一,包括: 1. **第i层的节点数**:二叉树的第i层最多有2^(i-1)个节点。 2. **深度与节点数的关系**:深度为k的二叉树最多有2^k-1个节点。 3. **终端节点与度为2的节点数关系**:对于...
### 东北大学数据结构实验3:树和二叉树 #### 实验背景 本次实验是针对东北大学计算机专业本科生的数据结构课程中的一项实践任务。实验的主要目的是帮助学生深入理解和掌握树形数据结构中的两种基本类型——树...