一、常见用语

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. assert 笔记

    目录 什么是assert? assert使用 assert错误使用 什么是assert? Python 的 assert 语句是一个 debug 的好工具,主要用于测试一个条件是否满足.如果测试的条件 ...

  2. element-ui练习使用总结

    <el-row> <el-col class="borderRed" :span="24"> <div class="g ...

  3. 用python来抓取“煎蛋网”上面的美女图片,尺度很大哦!哈哈

    所用Python环境为:python 3.3.2   用到的库为:urllib.request    re 废话不多说,先上代码: import urllib.request import re #获 ...

  4. NFFM的原理与代码

    本篇深入分析郭大nffm的代码 TensorFlow计算图 计算图的构建 ones = tf.ones_like(emb_inp_v2) mask_a = tf.matrix_band_part(on ...

  5. 【零基础】快速入门爬虫框架HtmlUnit

    迅速的HtmlUnit htmlunit是一款开源的web页面分析工具,理论上来说htmlunit应用于网页的自动化测试,但是相对来说更多人使用它来进行小型爬虫的快速开发.使用htmlunit进行爬虫 ...

  6. Android__adb 命令大全

    ADB 即 Android Debug Bridge,Android调试桥.ADB工作方式比较特殊,采用监听Socket TCP 端口的方式让IDE和Qemu通讯,默认情况下adb会daemon相关的 ...

  7. ionic3引用外部插件--百度地图及echart报表的使用

    前言 ionic3提供的组件已经相当丰富咯,但是事实上有些特殊的需求,比如使用百度地图,或者第三方插件echart报表插件是,就不能用传统的方式去使用第三方插件咯,如何在Ionic3项目中使用第三方J ...

  8. JDBC与ODBC

     ODBC(Open Database Connectivity)是一组对数据库访问的标准API,这些API通过SQL来完成大部分任务,而且它本身也支持SQL语言,支持用户发来的SQL.ODBC定义了 ...

  9. Permission权限大全

    访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES ,读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permiss ...

  10. WPF Win32 API 嵌入Form 窗体

    WIn32 API: public class Win32Native { [DllImport("user32.dll", SetLastError = true, CharSe ...