版权声明:本文出自汪磊的博客,未经作者允许禁止转载。

之前的篇章主要讲解了数据结构中的线性结构,所谓线性结构就是数据与数据之间是一对一的关系,接下来我们就要进入非线性结构的世界了,主要是树与图,好了接下来我们将会了解到树以及二叉树,二叉平衡树,赫夫曼树等原理以及java代码的实现,先从最基础的开始学习吧。

一、树

树的定义:

树是n(n>=0)个结点的有限集合。

当n=0时,集合为空,称为空树。

在任意一颗非空树中,有且仅有一个特定的结点称为根。

当n>1时,除根结点以外的其余结点可分成m(m>=0)个不相交的有限结点集合T1,T2….Tm.其中每个集合本身也是一棵树,称为根的子树。

如下图就是一棵树:

可以看到,树这种数据结构数据之间是一对一或者一对多关系,不再是一对一的关系

在上图中节点A叫做整棵树的根节点,一棵树中只有一个根节点。

根节点可以生出多个孩子节点,孩子节点又可以生出多个孩子节点。比如A的孩子节点为B和C,D的孩子节点为G,H,I。

每个孩子节点只有一个父节点,比如D的父节点为B,E的父节点为C。

好了,关于树的定义介绍到这,很简单。

二、树的相关术语

节点的度

节点含有的子树个数,叫做节点的度。度为0的节点成为叶子结点或终端结点。比如上图中D的度为3,E的度为1.

G,H,I,J的度为0,叫做叶子结点。

树的度

一棵树中 最大节点的度树的度。比如上图中树的度为3

结点的层次

从根结点算起,为第一层,其余依次类推如上图。B,C的层次为2,G,H的层次为4。

树中节点的最大层次称为树的高度或深度。上图中树的高度或深度为4

三、树的存储结构

简单的顺序存储不能满足树的实现,需要结合顺序存储和链式存储来解决。

树的存储方式主要有三种:

双亲表示法:每个节点不仅保存自己数据还附带一个指示器指示其父节点的角标,这种方式可以用数组来存储。

如图:

这种存储方式特点是:查找一个节点的孩子节点会很麻烦但是查找其父节点很简单。

孩子表示法:每个节点不仅保存自己数据信息还附带指示其孩子的指示器,这种方式用链表来存储比较合适。

如图:

这种存储方式特点是:查找一个节点的父亲节点会很麻烦但是查找其孩子节点很简单。

理想表示法:数组+链表的存储方式,把每个结点的孩子结点排列起来,以单链表方式连接起来,则n个孩子有n个孩子链表,如果是叶子结点则此链表为空,然后n个头指针又组成线性表,采用顺序存储方式,存储在一个一维数组中。

如图:

这种方式查找父节点与孩子结点都比较简便。

以上主要介绍了树的一些概念以及存储方式介绍,实际我们用的更多的是二叉树,接下来我们看下二叉树。

四、二叉树的概念

二叉树定义:二叉树是n(n>=0)个结点的有限集合,该集合或者为空,或者由一个根结点和两课互不相交的,分别称为根结点左子树和右子树的二叉树组成。

用人话说,二叉树是每个节点至多有两个子树的树。

如图就是一颗二叉树:

五、特殊二叉树

斜树:所有结点只有左子树的二叉树叫做左斜树,所有结点只有右子树的二叉树叫做右斜树。

如图:

满二叉树:在一棵二叉树中,所有分支结点都有左子树与右子树,并且所有叶子结点都在同一层则为满二叉树。

如图:

完全二叉树:所有叶子节点都出现在 k 或者 k-1 层,而且从 1 到 k-1 层必须达到最大节点数,第 k 层可是不是慢的,但是第 k 层的所有节点必须集中在最左边。

如图:

 六、二叉树的遍历

二叉树的遍历主要有三种:先序遍历,中序遍历,后续遍历,接下来我们挨个了解一下。

先序遍历:先访问根结点,再先序遍历左子树,再先序遍历右子树。

如图所示:

先序遍历结果为:ABDGHCEIF

中序遍历:先中序遍历左子树,再访问根结点,再中序遍历右子树。

如图:

中序遍历结果为:GDHBAEICF

后序遍历:先后序遍历左子树,再后序遍历右子树,再访问根结点。

如图:

后序遍历结果:GHDBIEFCA

七、java实现二叉树

先来看看每个结点类:

  1. public class TreeNode{
  2. private String data;//自己结点数据
  3. private TreeNode leftChild;//左孩子
  4. private TreeNode rightChild;//右孩子
  5.  
  6. public String getData() {
  7. return data;
  8. }
  9.  
  10. public void setData(String data) {
  11. this.data = data;
  12. }
  13.  
  14. public TreeNode(String data){
  15. this.data = data;
  16. this.leftChild = null;
  17. this.rightChild = null;
  18. }
  19. }

很简单,每个结点信息包含自己结点数据以及指向左右孩子的指针(为了方便,我这里就叫指针了)。

二叉树的创建

我们创建如下二叉树:

代码实现:

  1. public class BinaryTree {
  2. private TreeNode root = null;
  3.  
  4. public TreeNode getRoot() {
  5. return root;
  6. }
  7.  
  8. public BinaryTree(){
  9. root = new TreeNode("A");
  10. }
  11.  
  12. /**
  13. * 构建二叉树
  14. * A
  15. * B C
  16. * D E F G
  17. */
  18. public void createBinaryTree(){
  19. TreeNode nodeB = new TreeNode("B");
  20. TreeNode nodeC = new TreeNode("C");
  21. TreeNode nodeD = new TreeNode("D");
  22. TreeNode nodeE = new TreeNode("E");
  23. TreeNode nodeF = new TreeNode("F");
  24. TreeNode nodeG = new TreeNode("G");
  25. root.leftChild = nodeB;
  26. root.rightChild = nodeC;
  27. nodeB.leftChild = nodeD;
  28. nodeB.rightChild = nodeE;
  29. nodeC.leftChild = nodeF;
  30. nodeC.rightChild = nodeG;
  31. }
  32. 。。。。。。。
  33. }

创建BinaryTree的时候就已经创建根结点A,createBinaryTree()方法中创建其余结点并且建立相应关系。

获得二叉树的高度

树中节点的最大层次称为树的高度,因此获得树的高度需要递归获取所有节点的高度,取最大值。

  1. /**
  2. * 求二叉树的高度
  3. * @author Administrator
  4. *
  5. */
  6. public int getHeight(){
  7. return getHeight(root);
  8. }
  9.  
  10. private int getHeight(TreeNode node) {
  11. if(node == null){
  12. return 0;
  13. }else{
  14. int i = getHeight(node.leftChild);
  15. int j = getHeight(node.rightChild);
  16. return (i<j)?j+1:i+1;
  17. }
  18. }

获取二叉树的结点数

获取二叉树结点总数,需要遍历左右子树然后相加

  1. /**
  2. * 获取二叉树的结点数
  3. * @author Administrator
  4. *
  5. */
  6. public int getSize(){
  7. return getSize(root);
  8. }
  9.  
  10. private int getSize(TreeNode node) {
  11. if(node == null){
  12. return 0;
  13. }else{
  14. return 1+getSize(node.leftChild)+getSize(node.rightChild);
  15. }
  16. }

二叉树的遍历

二叉树遍历分为前序遍历,中序遍历,后续遍历,主要也是递归思想,下面直接给出代码

  1. /**
  2. * 前序遍历——迭代
  3. * @author Administrator
  4. *
  5. */
  6. public void preOrder(TreeNode node){
  7. if(node == null){
  8. return;
  9. }else{
  10. System.out.println("preOrder data:"+node.getData());
  11. preOrder(node.leftChild);
  12. preOrder(node.rightChild);
  13. }
  14. }
  15.  
  16. /**
  17. * 中序遍历——迭代
  18. * @author Administrator
  19. *
  20. */
  21. public void midOrder(TreeNode node){
  22. if(node == null){
  23. return;
  24. }else{
  25. midOrder(node.leftChild);
  26. System.out.println("midOrder data:"+node.getData());
  27. midOrder(node.rightChild);
  28. }
  29. }
  30.  
  31. /**
  32. * 后序遍历——迭代
  33. * @author Administrator
  34. *
  35. */
  36. public void postOrder(TreeNode node){
  37. if(node == null){
  38. return;
  39. }else{
  40. postOrder(node.leftChild);
  41. postOrder(node.rightChild);
  42. System.out.println("postOrder data:"+node.getData());
  43. }
  44. }

获取某一结点的父结点

获取结点的父节点也是递归思想,先判断当前节点左右孩子是否与给定节点信息相等,相等则当前结点即为给定结点的父节点,否则继续递归左子树,右子树。

  1. /**
  2. * 查找某一结点的父结点
  3. * @param data
  4. * @return
  5. */
  6. public TreeNode getParent(String data){
  7. //封装为内部结点信息
  8. TreeNode node = new TreeNode(data);
  9. //
  10. if (root == null || node.data.equals(root.data)){
  11. //根结点为null或者要查找的结点就为根结点,则直接返回null,根结点没有父结点
  12. return null;
  13. }
  14. return getParent(root, node);//递归查找
  15. }
  16.  
  17. public TreeNode getParent(TreeNode subTree, TreeNode node) {
  18.  
  19. if (null == subTree){//子树为null,直接返回null
  20. return null;
  21. }
  22. //判断左或者右结点是否与给定结点相等,相等则此结点即为给定结点的父结点
  23. if(subTree.leftChild.data.equals(node.data) || subTree.rightChild.data.equals(node.data)){
  24. return subTree;
  25. }
  26. //以上都不符合,则递归查找
  27. if (getParent(subTree.leftChild,node)!=null){//先查找左子树,左子树找不到查询右子树
  28. return getParent(subTree.leftChild,node);
  29. }else {
  30. return getParent(subTree.rightChild,node);
  31. }
  32. }

八、总结

以上总结了树与二叉树的一些概念,重点就是二叉树的遍历以及java代码实现,比较简单,没什么多余解释,下一篇了解一下赫夫曼树以及二叉排序树。

声明:文章将会陆续搬迁到个人公众号,以后文章也会第一时间发布到个人公众号,及时获取文章内容请关注公众号

Android版数据结构与算法(六):树与二叉树的更多相关文章

  1. Android版数据结构与算法(七):赫夫曼树

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 近期忙着新版本的开发,此外正在回顾C语言,大部分时间没放在数据结构与算法的整理上,所以更新有点慢了,不过既然写了就肯定尽力将这部分完全整理好分享出 ...

  2. Android版数据结构与算法(一):基础简介

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 一.前言 项目进入收尾阶段,忙忙碌碌将近一个多月吧,还好,不算太难,就是麻烦点. 数据结构与算法这个系列早就想写了,一是梳理总结,顺便逼迫自己把一 ...

  3. Android版数据结构与算法(五):LinkedHashMap核心源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 上一篇基于哈希表实现HashMap核心源码彻底分析 分析了HashMap的源码,主要分析了扩容机制,如果感兴趣的可以去看看,扩容机制那几行最难懂的 ...

  4. Android版数据结构与算法(四):基于哈希表实现HashMap核心源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 存储键值对我们首先想到HashMap,它的底层基于哈希表,采用数组存储数据,使用链表来解决哈希碰撞,它是线程不安全的,并且存储的key只能有一个为 ...

  5. Android版数据结构与算法(三):基于链表的实现LinkedList源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. LinkedList 是一个双向链表.它可以被当作堆栈.队列或双端队列进行操作.LinkedList相对于ArrayList来说,添加,删除元素效 ...

  6. Android版数据结构与算法(二):基于数组的实现ArrayList源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本片我们分析基础数组的实现--ArrayList,不会分析整个集合的继承体系,这不是本系列文章重点. 源码分析都是基于"安卓版" ...

  7. Android版数据结构与算法(八):二叉排序树

    本文目录 前两篇文章我们学习了一些树的基本概念以及常用操作,本篇我们了解一下二叉树的一种特殊形式:二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree) ...

  8. JavaScript 版数据结构与算法(二)队列

    今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...

  9. 数据结构与算法——AVL树类的C++实现

    关于AVL树的简单介绍能够參考:数据结构与算法--AVL树简单介绍 关于二叉搜索树(也称为二叉查找树)能够參考:数据结构与算法--二叉查找树类的C++实现 AVL-tree是一个"加上了额外 ...

随机推荐

  1. vue中keep-alive的用法

    1.keep-alive的作用以及好处 在做电商有关的项目中,当我们第一次进入列表页需要请求一下数据,当我从列表页进入详情页,详情页不缓存也需要请求下数据,然后返回列表页,这时候我们使用keep-al ...

  2. Python_从字符串中提取号码

    import re telNumber = '''Suppose my Phone No. is 0535-1234567,yours is 010-12345678,his is 025-87654 ...

  3. 利用Swagger2自动生成对外接口的文档

    一直以来做对外的接口文档都比较原始,基本上都是手写的文档传来传去,最近发现了一个新玩具,可以在接口上省去不少麻烦. swagger是一款方便展示的API文档框架.它可以将接口的类型最全面的展示给对方开 ...

  4. https://doc.opensuse.org/projects/kiwi/doc/

    KIWI 是用于创建操作系统映像的系统.映像是带有一个文件的目录,该文件包含操作系统.其应用程序与配置.操作系统的文件系统结构.可能的附加元数据,以及(取决于映像类型)磁盘几何属性和分区表数据.通过 ...

  5. SSM-Spring-12:Spring中NameMatchMethodPointcutAdvisor名称匹配方法切入点顾问

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- advice 是通知advisor 是顾问 顾问(Advisor) 通知Advice是Spring提供的一种切 ...

  6. .deb软件包的安装和软件的卸载

    前言: .deb格式的软件包是Debian和Ubuntu等Linux发行版软件安装包的文件扩展名. 使用.deb格式软件安装包安装软件 命令如下: sudo dpkg -i package_file. ...

  7. 在 Docker 容器中运行应用程序

    案例说明 运行 3 个容器,实现对网站的监控. 三个容器的说明: 容器 web: 创建自 nginx 映像,使用 80 端口,运行于后台,实现 web 服务. 容器 mailer: 该容器中运行一个 ...

  8. 你不知道的JavaScript--Item22 Date对象全解析

    本篇主要介绍 Date 日期和时间对象的操作. 1. 介绍 1.1 说明 Date对象,是操作日期和时间的对象.Date对象对日期和时间的操作只能通过方法. 1.2 属性 无: Date对象对日期和时 ...

  9. java之集合Collection 详解之4

    package cn.itcast_04; public class Student { private String name; private int age; public Student() ...

  10. main.go

    package main import (     "flag"     "fmt"     "log"     "os" ...