二叉树遍历概念和算法

遍历(Traverse):

  所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。

  从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。

  因此,在任一给定结点上,可以按某种次序执行三个操作:

    ⑴ 访问结点本身(D),
    ⑵ 遍历该结点的左子树(L),
    ⑶ 遍历该结点的右子树(R)。
 
  先序/根遍历DLR:根   左子树     右子树
  中序/根遍历LDR:左子树   根     右子树
  后根/序遍历LRD:左子树     右子树  根
 
  注意:由于树的递归定义,其实对三种遍历的概念其实也是一个递归的描述过程
 

算法实现:

二叉树结点类

/**
* 二叉链表的结点
* @author shangyang
*
*/
public class Node { Object value; // 结点值
Node leftChild; // 左子树的引用
Node rightChild; // 右子树的引用 public Node(Object value) {
super();
this.value = value;
} public Node(Object value, Node leftChild, Node rightChild) {
super();
this.value = value;
this.leftChild = leftChild;
this.rightChild = rightChild;
} @Override
public String toString() {
return "Node [value=" + value + ", leftChild=" + leftChild + ", rightChild=" + rightChild + "]";
}
}

二叉树方法接口类

/**
* 二叉树的接口
* 可以有不同的实现类,每个类可以使用不同的存储结构,比如顺序结构、链式结构
* @author shangyang
*
*/
public interface BinaryTree { /**
* 是否为空树
*/
public boolean isEmpty(); /**
* 树结点数量
*/
public int size(); /**
* 获取树的高度
*/
public int getHeight(); /**
* 查询指定值的结点
* @param value
* @return
*/
public Node findKey(Object value); /**
* 前序递归遍历
*/
public void preOrderTraverse(); /**
* 中序递归遍历
*/
public void inOrderTraverse(); /**
* 后序递归遍历
*/
public void postOrderTraverse(); /**
* 按照层次遍历(借助队列)
*/
public void levelOrderByStack(); /**
* 中序非递归遍历
*/
public void inOrderByStack();
}

二叉树接口类

实现二叉树接口类

创建树的根对象,并写出构造函数。

public class LinkedBinaryTree implements BinaryTree {

    private Node root;    // 根结点

    public LinkedBinaryTree() {
} public LinkedBinaryTree(Node root) {
this.root = root;
}
}

创建二叉树

    // 创建一个二叉树
Node nodeF = new Node("F",null,null);
Node nodeE = new Node("E",null,null);
Node nodeD = new Node("D",null,null);
Node nodeC = new Node("C",nodeF,null);
Node nodeB = new Node("B",nodeD,nodeE);
Node nodeA = new Node("A",nodeB,nodeC); // 声明nodeA为根结点
BinaryTree btree = new LinkedBinaryTree(nodeA);

判断二叉树是否为空

为空返回true,不为空返回false

public boolean isEmpty() {
return root == null;
}

输出二叉树结点数量

运用递归的思想,二叉树结点树 = 左子树结点数量 + 右子树结点数量 + 1

  public int size() {
System.out.println("二叉树结点数量: ");
return this.size(root);
}
private int size(Node root) {
if(root == null) {
return 0;
} else {
// 获取左子树的数量
int nl = this.size(root.leftChild);
// 获取右子树的数量
int nr = this.size(root.rightChild);
// 返回左子树、右子树size之和并加1
return nl + nr + 1;
}
}

二叉树的深度(高度)

如果二叉树为空,则其深度为0。

如果二叉树只有根结点,无左右子树,则其深度为1。

如果二叉树结点数大于1,则用递归的思想计算其深度。二叉树的深度 = 左右子树的最大深度 + 1。

    public int getHeight() {
System.out.println("二叉树的高度是 :");
return this.getHeight(root);
}
private int getHeight(Node root) {
if(root == null) {
return 0;
} else {
// 获取左子树的高度
int nl = this.getHeight(root.leftChild);
// 获取右子树的高度
int nr = this.getHeight(root.rightChild);
// 返回左子树、右子树较大高度并加1
return nl > nr ? nl + 1 : nr + 1;
}
}

在二叉树中查找某个值

运用递归的思想,将要查找的值逐个与根结点,根结点的左子树和右子树的值进行比较,并进行返回。

    public Node findKey(Object value) {
return this.findKey(value,root);
}
private Node findKey(Object value,Node root) {
// 结点为空,可能是整个树的根结点,也可能是递归调用中叶子结点中左孩子和右孩子
if(root == null) {
return null;
} else if (root != null && root.value == value) {
return root;
} else { // 递归体
Node leftnode = this.findKey(value,root.leftChild);
Node rightnode = this.findKey(value, root.rightChild);
if(leftnode != null && leftnode.value == value) {
return leftnode;
} else if (rightnode != null && rightnode.value == value) {
return rightnode;
} else {
return null;
}
}
}

先序递归遍历

若二叉树非空,则依次执行如下操作:
  ⑴ 访问根结点;
  ⑵ 遍历左子树;
  ⑶ 遍历右子树。
    public void preOrderTraverse() {
// 输出根结点的值
if(root != null) {
System.out.print(root.value + " "); // 对左子树进行先序遍历
// 构建一个二叉树,根是左子树的根
BinaryTree leftTree = new LinkedBinaryTree(root.leftChild);
leftTree.preOrderTraverse(); // 对右子树进行先序遍历
// 构建一个二叉树,根是左子树的根
BinaryTree rightTree = new LinkedBinaryTree(root.rightChild);
rightTree.preOrderTraverse();
}
}

中序递归遍历

若二叉树非空,则依次执行如下操作:
  ⑴ 遍历左子树;
  ⑵ 访问根结点;
  ⑶ 遍历右子树。
    public void inOrderTraverse() {
System.out.println("中序遍历");
this.inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(Node root) {
if(root != null) {
// 遍历左子树
this.inOrderTraverse(root.leftChild);
// 输出根的值
System.out.print(root.value + " ");
// 遍历右子树
this.inOrderTraverse(root.rightChild);
}
}

后续递归遍历

若二叉树非空,则依次执行如下操作:
  ⑴ 遍历左子树;
  ⑵ 遍历右子树;
  ⑶ 访问根结点。
    public void postOrderTraverse() {
System.out.println("后序遍历");
this.postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(Node root) {
if(root != null) {
// 遍历左子树
this.postOrderTraverse(root.leftChild);
// 遍历右子树
this.postOrderTraverse(root.rightChild);
// 输出根的值
System.out.print(root.value + " ");
}
}

按照层次遍历(借助队列)

按照从上到下、从左到右的次序进行遍历。先遍历完一层,再遍历下一层,因此又叫广度优先遍历。

该方法可以借助java中提供queue队列接口来完成。LinkedList实现了该接口。

    public void levelOrderByStack() {
if(root == null)
return;
Queue<Node> queue = new LinkedList<Node>();
queue.add(root);
while(queue.size() != 0) {
int len = queue.size();
for(int i = 0; i < len; i++) {
Node temp = queue.poll();
System.out.print(temp.value + " ");
if(temp.leftChild != null)
queue.add(temp.leftChild);
if(temp.rightChild != null)
queue.add(temp.rightChild);
}
}
}

中序非递归遍历(借助栈)

(1) 若根结点不为空,则将其放如栈中,并判断其左子树是否为空。

(2) 若不为空,则将子树根结点放入栈中,并继续向下判断,直至左子树为空。

(3) 若栈中有结点,则将其取出,并对其右子树根结点进行(1)(2)步骤,直至无结点或栈中元素为空。

    public void inOrderByStack() {
// 创建栈
Deque<Node> stack = new LinkedList<Node>();
Node current = root;
while(current != null || !stack.isEmpty()) {
while(current != null) {
stack.push(current);
current = current.leftChild;
} if(!stack.isEmpty()) {
current = stack.pop();
System.out.print(current.value + " ");
current = current.rightChild;
}
}
}

学习笔记——二叉树相关算法的实现(Java语言版)的更多相关文章

  1. 0031 Java学习笔记-梁勇著《Java语言程序设计-基础篇 第十版》英语单词

    第01章 计算机.程序和Java概述 CPU(Central Processing Unit) * 中央处理器 Control Unit * 控制单元 arithmetic/logic unit /ə ...

  2. KMP算法的实现(Java语言描述)

    标签:it KMP算法是模式匹配专用算法. 它是在已知模式串的next或nextval数组的基础上执行的.如果不知道它们二者之一,就没法使用KMP算法,因此我们需要计算它们. KMP算法由两部分组成: ...

  3. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  4. golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换

    golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...

  5. MySQL学习笔记-事务相关话题

    事务机制 事务(Transaction)是数据库区别于文件系统的重要特性之一.事务会把数据库从一种一致状态转换为另一个种一致状态.在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都 ...

  6. TensorFlow学习笔记6-数值计算基础

    TensorFlow学习笔记6-数值计算 本笔记内容为"数值计算的基础知识".内容主要参考<Deep Learning>中文版. \(X\)表示训练集的矩阵,其大小为m ...

  7. Java学习笔记(十六)——Java RMI

    [前面的话] 最近过的好舒服,每天过的感觉很充实,一些生活和工作的技巧注意了就会发现,其实生活也是可以过的如此的有滋有味,满足现在的状况,并且感觉很幸福. 学习java RMI的原因是最近在使用dub ...

  8. Java学习笔记(五)——google java编程风格指南(中)

    [前面的话] 年后开始正式上班,计划着想做很多事情,但是总会有这样那样的打扰,不知道是自己要求太高还是自我的奋斗意识不够?接下来好好加油.好好学学技术,好好学习英语,好好学习做点自己喜欢的事情,趁着自 ...

  9. Java学习笔记(二一)——Java 泛型

    [前面的话] 最近脸好干,掉皮,需要买点化妆品了. Java泛型好好学习一下. [定义] 一.泛型的定义主要有以下两种: 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个 ...

随机推荐

  1. 根据excel表格字段生成sql语句

    根据excel表格字段生成sql语句 1.1 前言 根据excel表格字段生成sql语句主要是利用了excel的拼接函数 CONCATENATE .该实例主要以mysql脚本支持.实例需求如下:exc ...

  2. idea导入maven项目,找不到jar包,出现红色波浪线【转】

    参考链接 点击跳转

  3. Winsock编程基础1

    1.加载和释放Winsoke库 //所有Winsock函数都是从WS2_32.DLL导出,包含相应库文件#include <winsock2.h>#pragma comment(lib, ...

  4. [lua][openresty]代码覆盖率检测的解决方式

    废话在前 什么是代码覆盖率 来自百度百科 代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率. 开发人员为何关注? 在我们的开发过 ...

  5. 微信小程序setData()方法的详解以及对数组/json操作

    此篇文章是本人对setData方法的一些理解,是查阅文档和查找一些其他资料综述的,有所不足希望指正! 直接进入正题! 一.setData()方法: 1.参数接受一个对象,以key,value的形式表示 ...

  6. 又到毕业季,尚学堂喊你免费领取100个Java毕设项目(含源码视频),限时一周哦!

    你还在为毕设发愁?不知道该如何命题?不知道从哪里下手?担心毕设过不了影响毕业? 尚学堂首家隆重推出了刷爆朋友圈的毕设100个项目,别说你还没去下载观看!!最最重要的是:免费!免费!免费!而且限时一周! ...

  7. 流媒体协议(一):HLS 协议

    一.HLS 概述 HLS 全称是 HTTP Live Streaming,是一个由 Apple 公司提出的基于 HTTP 的媒体流传输协议,用于实时音视频流的传输.目前HLS协议被广泛的应用于视频点播 ...

  8. [Swift]LeetCode214. 最短回文串 | Shortest Palindrome

    Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. ...

  9. [Swift]LeetCode488. 祖玛游戏 | Zuma Game

    Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), gre ...

  10. [Swift]LeetCode767. 重构字符串 | Reorganize String

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...