前言:

现在安卓面试,对于数据结构的问题也越来越多了,也经常看到别人发的面试题都是问什么红黑树,二叉树查找等,所以我们虽然不会马上就会各种难的面试题,但起码树的基础知识还是要会的,这样才能去进一步学。

贴上最近看到的一个介绍图片:

Android技能书系列:

Android基础知识

Android技能树 — 动画小结

Android技能树 — View小结

Android技能树 — Activity小结

Android技能树 — View事件体系小结

Android技能树 — Android存储路径及IO操作小结

Android技能树 — 多进程相关小结

Android技能树 — Drawable小结

数据结构基础知识

Android技能树 — 数组,链表,散列表基础小结

Android技能树 — 树基础知识小结(一)

算法基础知识

Android技能树 — 排序算法基础小结

本文主要讲关于树的基础知识。

树(Tree)是n(n>=0)个结点的有限集。n=0时称为空树。在任意一棵非空树中:(1)有且仅有一个特定的称为根(Root)的结点;(2)当n>1时,其余结点可分为m(m>O)个互不相交的有限集T1、T2、……、 Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)

基础知识

结点

根据上面的基础知识我画了一个归总的图(这样我就不需要写文字介绍了,啊哈哈):

树结构特点

还是用自己画的图来说明:

存储结构

在Android技能树 — 数组,链表,散列表基础小结中,我们介绍了线性存储,链式存储,我们的树可以充分用二者来结合表示。

我们统一来用上面各种方式来表示下面这个树的存储结构:

双亲表示法:

在每个结点中,附设一个指示器指示其双亲结点在数组中的位置。

因为有十一个结点,所以我们的index为0-10,然后index位置中存储(data + parent的index值),结果如下图所示:

这里我们发现根据index里面的parent指针,很容易知道父结点,但是比如我问知道了E结点,想知道它的子结点是哪几个,就不知道了,只能通过整个结构的遍历。

当然我们可以变相的 多加一个指针:

如果我们又比较关注兄弟结点之间的关系,可以增加一个右兄弟域来体现兄弟关系:

孩子链表表示法:

把每个结点的孩子结点排列起来,以单链表作存储结构,则n 个结点有n个孩子链表,如果是叶子结点,则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。

用孩子表示法表示我们上面的树,结构如下:

所以我们的结点结构有二种: 1.表头数组的表头结点:

  1. 孩子链表的孩子结点:

但是这样子对于查找某个结点的孩子,或者找某个结点的兄弟都方便,但似乎如果要找某个结点的双亲结点就麻烦了。所以我们可以结合上面讲过的《双亲表示法》

双亲孩子表示法:

把上面二个方法结合就可以了。

孩子兄弟表示法:

任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。 所以设置二个指针,分别指向该结点的第一个孩子和此结点的右兄弟

所以和上面类似,只是我们存了不同的二个指针(从方法名字就知道,<孩子><兄弟>法,一个孩子,一个兄弟,二个指针)。

我们把上面的树按照这种方式实现:

森林:

继续画个图来说明,省得打字了,嘿嘿:

分类

树也是会根据不同条件,做了分类,我们来了解一下。

那有序树和无序数的区别在于哪里呢?

如果将树中结点的各子树看成从左至右是有次序的,不能互换,则成为有序树,否则就是无序树

比如我们只是单纯的表示一个家族的关系:

比如只是说明A的孩子有B跟C,这时候B和C换了位置叶 没关系,这时候就是无序树。

但是如果我们这个家族谱是按照年龄来排序(长子,次子),那这时候B和C就不能换位置了,这时候就是有序树。

但是我们平常说的树通常都是指的有序树,而有序树有很多分类,比较多的就是二叉树。

二叉树:

基本形态:

二叉树性质:

其实这个类似与我们以前数学课上要背的数学公式,大家可以自己画个二叉树,然后试着上面的公式比对下,是不是正确。

遍历二叉树:

二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问依次且仅被访问一次。

前序遍历:

单单看这个图,其实换成我,我也看不懂规律,但是我们只需要懂得其中的规则就行。

伪代码:遍历(结点对象 t){if( t == null){return;}//第一步,实现某个业务操作,比如我们是打印结点字符串。print(t)//第二步,递归方式继续调用该方法遍历左孩子遍历(t.左孩子)//第三步,递归方式继续调用该方法遍历右孩子遍历(t.右孩子)
}
复制代码

我们看到因为print在其他方法的前面,所以叫前序遍历。我们现在传入根结点到这个方法,然后依次打印并且递归,就会发现,就是图上的顺序。

中序遍历:
伪代码:遍历(结点对象 t){if( t == null){return;}//第一步,递归方式继续调用该方法遍历左孩子遍历(t.左孩子)//第二步,实现某个业务操作,比如我们是打印结点字符串。print(t)       //第三步,递归方式继续调用该方法遍历右孩子遍历(t.右孩子)
}
复制代码

我们发现只要把我们的打印语句放在中间,就是中序遍历了。

后序遍历:
伪代码:遍历(结点对象 t){if( t == null){return;}//第一步,递归方式继续调用该方法遍历左孩子遍历(t.左孩子)//第二步,递归方式继续调用该方法遍历右孩子遍历(t.右孩子)//第三步,实现某个业务操作,比如我们是打印结点字符串。print(t)
}
复制代码

我们发现只要把我们的打印语句放在最后,就是后序遍历了。

二叉树分类:

斜树:
完全二叉树与满二叉树:

一棵深度为k,且有 2^(k+1) - 1 个节点的二叉树称为满二叉树,这种树的特点是每一层上的节点数都是最大节点数。

而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树。

满二叉树
完全二叉树
平衡二叉树:

这块知识很多,后期补上。

排序二叉树:

这块知识很多,后期补上。

线索二叉树:

n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。

这里一定要说明一个知识点:什么是前驱和后继。

网上很多人都是对这个解释太过于简单以至于很多人理解错误,比如:

假设我们现在有这个一个二叉树:

我现在问 I 的前驱是谁,后继是谁,很多人就单纯的从树的形状上来看,也就是看 I 的上一个结点是D,所以前驱是D, I 没有后面的子结点,所以后驱为空。这种回答是错误的。我们在 Android技能树 — 数组,链表,散列表基础小结文中提到过前驱和后继:

比如双向链表就是有前驱和后继。那我们单纯看这棵树是看不出来的,我们要先把树按照某个遍历方式的时候,把它用这种链表形式摆列,然后才能知道某个结点的前驱和后继是什么,比如上面的图我们用中序遍历,我们得到的是:HDIBJEAFCG,这时候 I 的前继是D,后继是B。

我们在二叉树存储结构中,有二个指针指向它的二个子结点。

但是可能只有一个子结点,或者没有子结点,这样这个空的指针存储就浪费了,我们可以在这个指针里面存这个结点的前驱或者后继结点的指针。

但是这时候又有一个问题,就是我们不知道这个点目前到底放的是前驱的还是左子结点的指针,所以我们还需要一个参数来说明当前这个位置放的是哪个的指针。

  1. 当ltag为0的时候,说明lchild是该结点的左孩子的指针,为1的时候说明lchild是该结点的前驱。
  2. 当rtag为0的时候,说明rchild是该结点的右孩子的指针,为1的时候说明rchild是该结点的后继。

存储结构:

二叉树顺序存储结构:

我们把二叉树补充为一个满二叉树,然后相应的填入一个一维数组即可。

二叉链表:

二叉树每个结点最多又二个孩子,所以为它设计一个数据域和二个指针域。

三叉链表:

改进于二叉链表,增加父节点的指引,能更好地实现节点间的访问

结语:

本文并没有写完,内容太多,后面再陆续补上去。哪里写错了,欢迎指出。。。谢谢。

参考:

《大话数据结构》

《维基百科》

Android技能树 — 树基础知识小结(一)相关推荐

  1. Android技能树 — 树基础知识小结(一),kotlin开源项目

    根据上面的基础知识我画了一个归总的图(这样我就不需要写文字介绍了,啊哈哈): [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zd87TfMP-1637304075403 ...

  2. 好程序员分享24个canvas基础知识小结

    好程序员分享24个canvas基础知识小结,非常全面详尽,推荐给大家. 现把canvas的知识点总结如下,以便随时查阅. 1.填充矩形 fillRect(x,y,width,height); 2.绘制 ...

  3. 好程序员分享24个canvas基础知识小结 1

    好程序员分享24个canvas基础知识小结,非常全面详尽,推荐给大家. 现把canvas的知识点总结如下,以便随时查阅. 1.填充矩形 fillRect(x,y,width,height); 2.绘制 ...

  4. WinCE流驱动基础知识小结

    WinCE流驱动基础知识小结 1.基础知识: 1)系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件细节,在应用程序看来硬件只 ...

  5. 哈夫曼树基础知识总结

    哈夫曼树的基本概念 路径长度最短的树不一定是完全二叉树 满二叉树不一定是哈夫曼树 哈夫曼树中权越大的叶子离根越近 具有相同带权结点的哈夫曼树不唯一 哈夫曼树基础知识总结 哈夫曼树的结点度数为0或2,没 ...

  6. Android 系统 wifi基础知识

    第3章 Wi-Fi基础知识 本章所涉及的源代码文件名及位置 ·wireless.h external/ kernel-headers/ original/ linux/ wireless.h ·dri ...

  7. Android系统学习---基础知识

    目录 1.基础知识Android消息处理机制 android线程 方法一(创建线程) 方法二(创建线程)

  8. Android录音-音频基础知识

    音频基础知识 文章目录 音频基础知识 一.采样率 二.采样位深 三.比特率 四.声道(单声道.双声道) 五.PCM元数据 音频基本概念:采样率.采样位深.比特率.声道.PCM 一.采样率 采样率(也称 ...

  9. Android学习之基础知识十一 —运用手机多媒体

    一.使用通知(Notification) 通知(Notification)是Android系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助 ...

最新文章

  1. 马少平、周枫、王小川、楼天城、唐文斌……清华计算机系与人工智能的40年...
  2. linux yum 离线安装rpm包
  3. 设计模式你怎么看?--抽象工厂模式
  4. 【盘它!】那些让效率MAX的工具和方法(Mac篇)
  5. java多线程对数组求和_java 多线程 求和
  6. 现代操作系统原理与实践02:硬件结构
  7. Min(BZOJ 1441)
  8. LabVIEW 读写和缩放音频文件
  9. 创建一个带目录的Word模板
  10. 深入计算机组成原理(二十七)SIMD:如何加速矩阵乘法
  11. 重要发布全总结丨一文看懂阿里云弹性计算年度峰会
  12. 图灵测试 Alan Turning
  13. iOS 7 之Airdrop 分享
  14. SSL证书中DV、OV、EV证书的区别有哪些
  15. Android studio的下载和安装
  16. 柏林水厂资产管理RFID跟踪管理系统应用
  17. css:单行超出显示三点省略号,总是忘,写个博客吧
  18. 怎样办理微信公众平台迁移公证?
  19. 条码软件如何自定义条码二维码的样式
  20. 【BZOJ2288】[POJ Challenge]生日礼物(线段树)

热门文章

  1. mysql linux err2003_远程连接linux下的mysql Err1045 Err2003解决办法
  2. mongodb查询不带表名_原创 | MongoDB常用指令
  3. import 快捷键 自动调整顺序_一文搞定PPT中的快捷键
  4. 典型相关分析(cca)原理_CCA典型关联分析原理与Python案例
  5. 根据坐标点鼠标 不移动_工地基本功:别管一致不一致,CAD坐标一次全部导入...
  6. 转元组 python_Python基础教程,第三讲,列表和元组
  7. 图像降噪算法——时域降噪算法
  8. 【通知】2020年有三AI-CV夏季划升级,更多项目,更高难度,更加落地
  9. 【模型解读】resnet中的残差连接,你确定真的看懂了?
  10. 全球及中国第三方供应链管理行业发展状况与规模前景分析报告2022-2027年