一、常见用语

1、逻辑结构:描述数据之间逻辑上的相关关系。分为线性结构(如,字符串),和非线性结构(如,树,图)。

2、物理结构:描述数据的存储结构,分为顺序结构(如,数组)和链式结构。

3、结点的度:一个节点子树(即分支)个数。

4、叶结点:也称为终端节点,指度为0的节点。

5、树的深度(高度):树中结点层次的最大值。

6、有序树:子树有先后次序之分(我的理解就是左右节点次序不可以颠倒)。

7、同构:将节点适当重命名,即可得两颗完全相同的树

8、孩子节点:一个节点的直接后继节点。

9、双亲节点:一个节点的直接前驱节点。

二、二叉树中的概念

1、二叉树:满足以下两个条件的树称为二叉树

①节点的度不可以超过2

②节点的孩子节点次序不可颠倒

2、满二叉树:每层得节点数都是满的,即2i-1

3、完全二叉树:节点1~n分别对应于满二叉树的节点1~n

4、完全二叉树的性质:

(1)若节点序号为i(i>1),则其双亲节点序号为i/2。(这里是整除)

(2)若节点序号为i(i>=1),则其左子节点序号为2i。

(3)若节点序号为i (i>=1),则其右子节点序号为2i+1。

三、二叉树的操作

 1、二叉树节点的存储结构

public class TreeNode {
String data;
TreeNode LChild;
TreeNode RChild;
TreeNode(String data) {
this.data = data;
}
public String toString() {
return data;
}
}

 2、创建二叉树

使用前序遍历创建二叉树是比较合适,按照逻辑,总要先创建根节点在创建左右子树,总不能还没有创建根节点就把root.LChild传递出去吧。

private static String[] tree = {"A","B",".",".","C","D",".",".","."};
private static int i = 0;
//先序创建二叉树是比较合适的
TreeNode inOrderCreateBTree() {
TreeNode bt = null;
String s = tree[i++];
if(s == ".") {
return bt;
}else {
bt = new TreeNode(s);
bt.LChild = inOrderCreateBTree();
bt.RChild = inOrderCreateBTree();
return bt;
}
}

可以用非递归的方式建树,但是难度还是挺大的。

3、先序遍历

递归方式:

//递归法前序遍历二叉树
void preOrderPrintBTree(TreeNode bt) {
if(bt == null) {
System.out.print("." + " ");
}else {
System.out.print(bt + " ");
preOrderPrintBTree(bt.LChild);
preOrderPrintBTree(bt.RChild);
}
}

基于栈的非递归方式:

跟着思路写就好:事实上这就是一个代码的模板,三种遍历的代码在结构上都是差不多的。

①指针移到最左子孙节点,边移变打印,边入栈(入栈是为了保存双亲节点,以便访问右子树)。

while(p != null) {
System.out.print(p + " ");
stack.push(p);
p = p.LChild;
if(p == null) {
System.out.print("." + " ");
}
}

②栈不空,就出栈,p指针指向右子树。

if(!stack.isEmpty()) {
p = stack.pop();
p = p.RChild;
if(p == null) {
System.out.print("." + " ");
}
}

完整代码:

//基于栈的非递归法先序遍历二叉树
void preOrderPrintBTree1(TreeNode bt) {
if(bt == null) {
System.out.println("null tree");
}
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = bt;
while(!stack.isEmpty() || p != null) {
while(p != null) {
System.out.print(p + " ");
stack.push(p);
p = p.LChild;
if(p == null) {
System.out.print("." + " ");
}
}
if(!stack.isEmpty()) {
p = stack.pop();
p = p.RChild;
if(p == null) {
System.out.print("." + " ");
}
}
}
}

 4、中序遍历

递归法:

void inOrderPrint(TreeNode bt) {
if(bt == null) {
System.out.print("." + " ");
} else {
inOrderPrint(bt.LChild);
System.out.print(bt + " ");
inOrderPrint(bt.RChild);
}
}

非递归法:

前序遍历和中序遍历是查不多的,前者先打印后入栈,后者是先入栈后打印。

①p指针移到最左端,边移变入栈。

while(p != null) {
stack.push(p);
p = p.LChild;
}

②边出栈边打印,p指针指向右子树

if(!stack.isEmpty()) {
p = stack.pop();
System.out.print(p + " ");
}

完整代码:

void inOrderPrint1(TreeNode bt) {
if(bt == null) {
System.out.println(".");
}else {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = bt;
while(!stack.isEmpty() || p != null) {
while(p != null) {
stack.push(p);
p = p.LChild;
}
if(!stack.isEmpty()) {
p = stack.pop();
System.out.print(p + " ");
}
}
}
}

 5、后续遍历

递归:

void postOrderPrint(TreeNode bt) {
if(bt == null) {
System.out.print("." + " ");
}else {
postOrderPrint(bt.LChild);
postOrderPrint(bt.RChild);
System.out.print(bt + " ");
}
}

非递归:后续遍历的难点就在于要知道前一次访问的节点是左孩子还是右孩子,所以要设置一个前置指针pre。

①pcur指针移到最左端,边移边入栈

②pcur的有孩子被为null或者被访问过,则访问pcur,否则pcur要继续入栈,pcur指向其右孩子。

完整代码:

void postOrderPrint1(TreeNode bt) {
if(bt == null) {
System.out.print("." + " ");
}else {
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode pcur = bt;
TreeNode pre = null;
while(pcur != null) {
stack.push(pcur);
pcur = pcur.LChild;
}
while(!stack.isEmpty()) {
pcur = stack.pop(); if(pcur.RChild == null || pcur.RChild == pre) {
System.out.print(pcur + " ");
pre = pcur;
}else {
stack.push(pcur);
pcur = pcur.RChild;
while(pcur != null) {
stack.push(pcur);
pcur = pcur.LChild;
}
}
}
}
}

 6、二叉树的其他操作

(1)打印叶子节点

//前序遍历打印叶子节点
public static void preprintLeaves(TreeNode bt) {
if(bt == null) { }else {
if(bt.LChild == null && bt.RChild == null) {
System.out.print(bt + " ");
}
preprintLeaves(bt.LChild);
preprintLeaves(bt.RChild);
}
}

(2)求树的深度

//先序遍历求二叉树的深度
public static int preTreeDepth(TreeNode bt, int h) {
if(bt != null) {
if(h > depth) depth = h;
preTreeDepth(bt.LChild,h+1);
preTreeDepth(bt.RChild,h+1);
}
return depth;
}
//后续遍历求二叉树深度
public static int postTreeDepth(TreeNode bt) {
int hl = 0;
int hr = 0;
int max = 0;
if(bt == null) {
return 0;
}else {
hl = postTreeDepth(bt.LChild);
hr = postTreeDepth(bt.RChild);
max = Math.max(hr, hl);
return max + 1;
}
}

二叉树(Java实现)的更多相关文章

  1. 二叉树JAVA实现

    为了克服对树结构编程的畏惧感和神秘感,下定决心将二叉树的大部分操作实现一遍,并希望能够掌握二叉树编程的一些常用技术和技巧.关于编程实现中的心得和总结,敬请期待!~ [1]  数据结构和表示: 二叉树的 ...

  2. 剑指Offer:面试题23——从上往下打印二叉树(java实现)

    问题描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 思路: 按照层次遍历的方法,使用队列辅助. 1.将根结点加入队列. 2.循环出队,打印当前元素,若该结点有左子树,则将其加入队列,若 ...

  3. 剑指offer【04】- 重建二叉树(java)

    题目:重建二叉树 考点:树 题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6, ...

  4. 二叉树 Java 实现 前序遍历 中序遍历 后序遍历 层级遍历 获取叶节点 宽度 ,高度,队列实现二叉树遍历 求二叉树的最大距离

    数据结构中一直对二叉树不是很了解,今天趁着这个时间整理一下 许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显 ...

  5. 数据结构之二叉树java实现

    二叉树是一种非线性数据结构,属于树结构,最大的特点就是度为2,也就是每个节点只有一个左子树和一个右子树.二叉树的操作主要为创建,先序遍历,中序遍历,后序遍历.还有层次遍历.遍历有两种方式,一是采用递归 ...

  6. 算法笔记_189:历届试题 横向打印二叉树(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 二叉树可以用于排序.其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树. 当遇到空子树 ...

  7. 非递归遍历二叉树Java版的实现代码(没写层次遍历)

    直接上代码呵呵,里面有注解 package www.com.leetcode.specificProblem; import java.util.ArrayList; import java.util ...

  8. 22.从上往下打印二叉树 Java

    题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路 就是二叉树的层序遍历.借助一个队列就可以实现.使用两个队列一个存放节点,一个存放值.先将根节点加入到队列中,然后遍历队列中的 ...

  9. 前序遍历构造已知二叉树(Java)

    public BiNode createBiTree() { Scanner input = new Scanner(System.in); int k = input.nextInt(); if(k ...

  10. 非递归遍历二叉树Java实现

    2018-10-03 20:16:53 非递归遍历二叉树是使用堆栈来进行保存,个人推荐使用双while结构,完全按照遍历顺序来进行堆栈的操作,当然在前序和后序的遍历过程中还有其他的压栈流程. 一.Bi ...

随机推荐

  1. redis基本介绍

    1.Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能(NOSQL)的key-value数据库,Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化 ...

  2. windows 安装python2.7

    下载:https://www.python.org/downloads/release/python-2716/ 安装即可. 设置环境变量 进入C:\Python27,修改python.exe 为py ...

  3. python国内镜像源

    让python pip使用国内镜像 国内源: 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pyp ...

  4. 使用 kubeadm 安装 kubernetes v1.16.0

    近日通过kubeadm 安装 kubernetes v1.16.0,踩过不少坑,现记录下安装过程. 安装环境: 系           统:CentOS Linux release 7.6 Docke ...

  5. JavaWeb_(Spring框架)在Struts+Hibernate框架中引入Spring框架

    spring的功能:简单来说就是帮我们new对象,什么时候new对象好,什么时候销毁对象. 在MySQL中添加spring数据库,添加user表,并添加一条用户数据 使用struts + hibern ...

  6. Could not initialize class sun.awt.X11GraphicsEnvironment异常处理

    原因导致: 经过Google发现很多人也出现同样的问题.从了解了X11GraphicEnvironment这个类的功能入手, 一个Java服务器来处理图片的API基本上是需要运行一个X-server以 ...

  7. 整个系统禁用复制功能下,js实现部分数据的复制功能

    需求背景:整个系统禁止复制,列表页操作栏新增按钮来复制数据列的手机号功能 感受下是怎么回事?看下效果 (GIF有点点烂)

  8. 使用django uwsgi 导致磁盘满

    lsof |grep delete |sort -nrk 7|more kill 掉这些进程

  9. IntelliJ IDEA 2017 上传本地项目至码云

    码云免费还挺好用,和Git类似.首先需要注册一个码云.这个就不介绍了. 点击加号,新建一个项目. 填写项目名称.  复制一下你的项目地址.  如图勾选.将项目至于git管理. 首先commit.快捷按 ...

  10. PHP AJAX 返回XML数据

    例子:利用AJAX间接访问数据库,查出Nation表中的数据,返回XML数据,并将Nation表中的数据显示在下拉列表框中 外层建一个下拉列表框 </select> JQurey代码 $( ...