写在前面

树这种数据结构在计算机世界中有广泛的应用,比如操作系统中用到了红黑树,数据库用到了B+树,编译器中的语法树,内存管理用到了堆(本质上也是树),信息论中的哈夫曼编码等等等等。而树的实现和他的操作集也是笔试面试中常见的考核项目。

树的实现

与C语言的结构体+指针的实现方式不同,Java中树的实现当然是基于类。以二叉树为例,树的实现可以用下面这样的形式:

 public class BinaryTree<T extends Comparable<T>> {
private BinaryTree<T> root;
//定义存储内容:内容、左子树、右子树
public class Node<T extends Comparable<T>>{
T data;
BinaryTree<T> left;
BinaryTree<T> right;
//也可以有父节点
BinaryTree<T> parent; public Node(T data, BinaryTree<T> left, BinaryTree<T> right, BinaryTree<T> parent) {
this.data = data;
this.left = left;
this.right = right;
this.parent = parent;
}
} //定义方法:增、删、查、改。 public boolean insert(int x){
...
}
public boolean delete(int x){
...
}
}

要注意,为了清晰树中数据的含义,我们一般不直接把树节点当做其成员变量,而是在其中新建内部类将其打包。针对子节点不止2个的多叉树,只需要把上面的left,right等合并成一个BinaryTree<T>类型的数组即可。

树的遍历

树的遍历应当是我们的基本功,里面涉及了后面图论算法中的深度优先搜索(DFS)广度优先搜索(BFS),因此虽然简单但也很重要。在树的遍历中,往往对应着递归算法和非递归算法(层序遍历除外)。递归算法往往能写出很精简的代码,但是运行过程中会占用大量的系统资源。因此,非递归算法在这一点上还是更有优势。我们也应该更着重记忆他的非递归算法。面试过程中,我们甚至可以和面试官讨论所要求的写法。

先来看看前中后序遍历递归写法

 public void preOrderTraversal(BinaryTree<T> tree){
if(tree==null) return;
System.out.print(tree.node.data+" ");
preOrderTraversal(tree.node.left);
preOrderTraversal(tree.node.right);
}
 //中序遍历
public void inOrderTraversal(BinaryTree<T> tree){
if(tree==null) return;
inOrderTraversal(tree.node.left);
System.out.print(tree.node.data+" ");
inOrderTraversal(tree.node.right);
}
 //后序遍历
public void pastOrderTraversal(BinaryTree<T> tree){
if(tree==null) return;
pastOrderTraversal(tree.node.left);
pastOrderTraversal(tree.node.right);
System.out.print(tree.node.data+" ");
}

看起来相当简单,也相当好记对吧。再来看非递归怎么在Java中实现:

树的前序遍历和中序遍历的非递归算法都是用堆栈来实现,具体实现如下。

 public void preOrderTraversal(){
Stack<BinaryTree<T>> st = new Stack<>();
BinaryTree<T> tmp = this;
while(tmp!=null || !st.empty()){
while(tmp!=null){
System.out.print(tmp.node.data+" ");
st.push(tmp);
tmp=tmp.node.left;//一路向左
}
if(!st.empty()){
tmp=st.pop();
tmp=tmp.node.right;//偶尔向右
}
}
System.out.println();
}
 public void inOrderTraversal(){
Stack<BinaryTree<T>> st = new Stack<>();
BinaryTree<T> tmp = this;
while(tmp!=null || !st.empty()){
while(tmp!=null){
st.push(tmp);
tmp=tmp.node.left;
}
if(!st.empty()){
tmp=st.pop();
//输出变到这里,仅此而已
System.out.println(tmp.node.data);
tmp=tmp.node.right;
}
}
}

后序遍历思路相似,由于后序遍历是第三次经过才进行输出(见上图),而上面的while循环和if代码块分别表示第一次见和第二次见,因此需要增加一个标志位在每一个节点,用来标明是不是在if代码块中第一次看见它。这么说并不明显,自己实现一遍应该会印象深刻一点。

 //后续非递归
public void PastOrderTraversal(){
BinaryTree<T> Tmp = this;
Stack<BinaryTree<T>> st = new Stack<>();
while(Tmp!=null || !st.empty()){
while(Tmp!=null){
st.push(Tmp);
Tmp=Tmp.node.left;
}
if(!st.empty()){//if代码块
Tmp=st.pop();
if(Tmp.node.IsFirstTraversal){//这里判断是不是第一次进if代码块
Tmp.node.IsFirstTraversal=false;//进来过了,置位false,下一次就可以输出了
st.push(Tmp);
Tmp=Tmp.node.right;
}
else{//不是第一次,输出
System.out.print(Tmp.node.data+" ");
}
}
}
}

层序遍历只有非递归写法,没有递归的方法。层序遍历利用的数据结构是队列遍历应该先从根节点开始,首先将根节点入队,然后开始执行循环:节点出队、访问节点(print)、左右儿子入队。

 //层序遍历
public void levelOrderTraversal(){
Queue<BinaryTree<T>> tQueue = new ArrayDeque<>();
BinaryTree<T> tmp = this;
tQueue.add(tmp);
while(!tQueue.isEmpty()){
tmp = tQueue.remove();
System.out.print(tmp.node.data+" ");
if(tmp.node.left!=null) tQueue.add(tmp.node.left);
if(tmp.node.right!=null) tQueue.add(tmp.node.right);
}
}

操作集

1.插入

     private BinaryTree<T> insert(BinaryTree<T> t, Node<T> n){
if(t==null) {
t = new BinaryTree<>();
t.node = n;
return t;
}
int cmp = n.data.compareTo(t.node.data);
if(cmp==0) return null;//节点存在
else if(cmp<0) t.node.left = insert(t.node.left, n);
else t.node.right = insert(t.node.right, n);
return t;
} public void insert(T x){
Node<T> n = new Node<>(x,null, null, null);
if(this.node==null){
this.node = n;
return;
}
insert(this,n);
}

2.查找

普通查找比较好实现,这个就是利用了二分查找的思想。

    /**
* 查找
* @param t 树
* @param x 查找的值
* @return 值所在树
*/
private BinaryTree<T> find(BinaryTree<T> t, T x){
int cmp = x.compareTo(t.node.data);
if(cmp==0){//找到了
return t;
}
else if(cmp<0) return find(t.node.left,x);
else return find(t.node.right,x);
} public BinaryTree<T> find(T x){
return find(this, x);
}

从Java看数据结构之——树和他的操作集的更多相关文章

  1. java项目——数据结构实验报告

    java项目——数据结构总结报告 20135315  宋宸宁 实验要求 1.用java语言实现数据结构中的线性表.哈希表.树.图.队列.堆栈.排序查找算法的类. 2.设计集合框架,使用泛型实现各类. ...

  2. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  3. (6)Java数据结构-- 转:JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析  http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...

  4. 学习javascript数据结构(四)——树

    前言 总括: 本文讲解了数据结构中的[树]的概念,尽可能通俗易懂的解释树这种数据结构的概念,使用javascript实现了树,如有纰漏,欢迎批评指正. 原文博客地址:学习javascript数据结构( ...

  5. [翻译]Linux 内核里的数据结构 —— 基数树

    目录 Linux 内核里的数据结构 -- 基数树 基数树 Radix tree Linux内核基数树API 链接 Linux 内核里的数据结构 -- 基数树 基数树 Radix tree 正如你所知道 ...

  6. AVL树的JAVA实现及AVL树的旋转算法

    1,AVL树又称平衡二叉树,它首先是一颗二叉查找树,但在二叉查找树中,某个结点的左右子树高度之差的绝对值可能会超过1,称之为不平衡.而在平衡二叉树中,任何结点的左右子树高度之差的绝对值会小于等于 1. ...

  7. 【转】Java学习---Java核心数据结构(List,Map,Set)使用技巧与优化

    [原文]https://www.toutiao.com/i6594587397101453827/ Java核心数据结构(List,Map,Set)使用技巧与优化 JDK提供了一组主要的数据结构实现, ...

  8. 【转载】图解Java常用数据结构(一)

    图解Java常用数据结构(一)  作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...

  9. Java同步数据结构之ConcurrentSkipListMap/ConcurrentSkipListSet

    引言 上一篇Java同步数据结构之Map概述及ConcurrentSkipListMap原理已经将ConcurrentSkipListMap的原理大致搞清楚了,它是一种有序的能够实现高效插入,删除,更 ...

随机推荐

  1. 安装ruby开发环境

    如何快速正确的安装 Ruby, Rails 运行环境 对于新入门的开发者,如何安装 Ruby, Ruby Gems 和 Rails 的运行环境可能会是个问题,本页主要介绍如何用一条靠谱的路子快速安装 ...

  2. 对于WebAssembly编译出来的.wasm文件js如何调用

    WebAssembly也叫浏览器字节码技术 这里就不过多的解释了网上很多介绍 主要是让大家知道在js里面如何调用执行它,我之前看WebAssemblyAPI时候反正是看得一脸懵逼 也是为了大家能更快的 ...

  3. vue+element UI如何导出excel表

    导出excel表应按如下规则 首先要先安装如下依赖 npm install --save xlsx npm install --save file-saver 接下在在你的代码中去引用这两个 impo ...

  4. Comet OJ 热身赛-principal

    这题的话,我们分析一下,入栈的操作是: 栈空 栈顶元素和当前操作元素不属于同一类括号 栈顶元素和当前操作元素属于同一类括号,但是并不是左括号在前,右括号在后 上面三个条件有任意一个满足都应该入栈,如果 ...

  5. 【Java_基础】cmd下使用java命令运行class文件提示“错误:找不到或无法加载主类“的问题分析

    1.问题如下 当在命令行使用java命令执行字节码文件时提示“错误:找不到或无法加载主类” 2. 问题分析 这是由于在运行时类的全名应该是包名+类名,例如在包net.xsoftlab.baike下的类 ...

  6. struts2命名空间与访问路径

    比如项目deom的struts.xml中有如下片段 Java代码 <package name="demo" extends="struts-default" ...

  7. 【支付宝支付】扫码付和app支付,回调验证签名失败问题

    在检查了参数排序,编码解码,文件编码等问题后,发现还是签名失败,最后找出原因: 扫码付和app支付采用的支付宝公钥不一样   Pid和公钥管理里面:   开放平台密钥界面和开放平台应用界面的密钥应该一 ...

  8. 简单几点让你快速了解python是什么

    1.python是什么 python是一种广泛使用的高级编程语言,属于通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年.可以视之为一种改良(加入一些其他编程语言的优点,如面向对象)的LIS ...

  9. 牛客网暑期ACM多校训练营(第四场)G Maximum Mode(思维)

    链接: https://www.nowcoder.com/login?callBack=%2Facm%2Fcontest%2F142%2FG 题意: 给定n个数, 要求删去恰好m个数后的最大总数是多少 ...

  10. 资产管理软件 GLPI的安装(转)

     资产管理系统GLPI的安装 2010-07-05 16:20:31 标签:休闲 资产管理系统 GLPI 职场 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则 ...