一、二叉树的定义及其主要特征

1.1 二叉树的概念

二叉树是另一种树形结构,其特点是每个结点最多含两棵子树(也就是说,二叉树的度≤2)。

二叉树是一种有序树,若将其左、右子树颠倒,则成为另一颗不同的二叉树。

二叉树可以为空

1.2 二叉树和度为2的有序树

在这里要区分一个概念,也就是二叉树和度为2的有序树之间的区别。

  1. 度为2的树至少有3个结点,而二叉树则可以是一颗空树
  2. 度为2的有序树的孩子结点,左右次序是相对于另一孩子结点而言的,若某个结点只有一个孩子结点,则这个结点就无须区分其左右次序。但,二叉树无论其孩子数是否为2,均需确定其左右次序,也就是说,二叉树的孩子结点的次序是绝对的。

1.3 几种特殊的二叉树

1. 满二叉树

一颗高度为h,且含有2h−12^h-12h−1个结点的二叉树就是一颗满二叉树。

满二叉树的特点:

  1. 每一层的结点个数为 2h−12^{h-1}2h−1
  2. 叶子结点之外的每个结点的度都是2
  3. 叶子结点都位于同一层
  4. 对整棵树按从1开始从上到下,自左向右编号,对于编号为i的结点,若有双亲,则双亲的位置 i2(向下取整)\frac{i}{2}(向下取整)2i​(向下取整),若有左孩子,则左孩子的编号为2i+12i+12i+1,若有右孩子,则右孩子的编号为2i+22i+22i+2,

2. 完全二叉树

设有一个高度为h,有n个结点的二叉树,当且仅当每个结点都与高度为h的满二叉树中编号1~n的结点一一对应时,就是一颗完全二叉树

完全二叉树的特点:

  1. 叶子结点只可能在层次最大的两层上出现,且对于最大层次中叶子结点都依次排列在该层最左侧的位置
  2. 若出现度为1的结点,有且仅有可能一个,且只有左孩子

3. 二叉排序树

一棵空树,或者是具有下列性质的二叉树:

  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  3. 左、右子树也分别为二叉排序树;

4. 平衡二叉树

树上任一结点的左子树和右子树的深度不大于1

二叉树的存储结构

顺序存储结构:用一组地址连续的存储单元存储。满二叉树和完全二叉树使用较为合适。其他树使用数组中可能有空结点

链式存储结构:用指针指向根结点的孩子结点。二叉树的存储结构一般有三个域:1. 数据域data,2. 左指针域left,3. 右指针域right

struct BinaryTreeNode{int data;BinaryTreeNode *left;BinaryTreeNode *right;
};

二叉树的遍历

示例树如下:

1. 先序遍历

若二叉树为空,则什么都不做,否则

  1. 访问根结点
  2. 先序遍历左结点
  3. 先序遍历右结点

以先序遍历方式遍历示例树,结果为:ABDECFG

void preorder(TreeNode *node, int layer) {if(!node) {return;}do something;preorder(node->left, layer + 1);preorder(node->right, layer + 1);
}

2. 中序遍历

若二叉树为空,则什么都不做,否则

  1. 先序遍历左结点
  2. 访问根结点
  3. 先序遍历右结点

以中序遍历方式遍历示例树,结果为:DBEAFCG

void inorder(TreeNode *node, int layer) {if(!node) {return;}preorder(node->left, layer + 1);do something;preorder(node->right, layer + 1);
}

3. 后序遍历

若二叉树为空,则什么都不做,否则

  1. 先序遍历左结点
  2. 先序遍历右结点
  3. 访问根结点

以后序遍历方式遍历示例树,结果为:DEBFCGA

void postorder(TreeNode *node, int layer) {if(!node) {return;}preorder(node->left, layer + 1);preorder(node->right, layer + 1);do something;
}

4. 层次遍历

要进行层次遍历,需要借助一个队列。先将二叉树根结点入队,然后出队,若它有左子树,则将左子树根结点入队;若它有右子树,则将右子树根结点入队。然后出队,对出队结点访问,如此反复,直到队列为空

以层序遍历方式遍历示例树,结果为:ABCDEFG

void Sequence(TreeNode *node) {queue<TreeNode *> q;q.push_back(node);while(!q.empty()) {TreeNode *root = node;q.pop();}
}

反过来讨论,给你一个中序序列和一个其他遍历序列能否构造出唯一一颗二叉树。答案是可以的。

如,先序序列:ABDECFG,中序序列:DBEAFCG

  1. 先序序列第1个就是根结点,那么在中序序列中,以A为界,整个字符串分为两节,分别是DBE和FCG
  2. 先序序列第2个就是其左子树的根结点,那么在中序序列中,以B为界,DBE字符串分为两节,分别是D和F,在B左边的就是B的左子树根结点,在B右边的就是B的右子树的根结点。
  3. 同理推得A的右子树的根结点,往复循环即可。

线索二叉树

在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。

线索链表解决了无法直接找到该结点在某种遍历序列中的前驱和后继结点的问题,解决了二叉链表找左、右孩子困难的问题。

在二叉树线索化时,通常规定:若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点

线索二叉树的存储结构:

struct ThreadBinaryTreeNode{int data;ThreadBinaryTreeNode *lchild;   // 指向左孩子结点ThreadBinaryTreeNode *rchild; // 指向右孩子结点int ltag;     // 0表示结点的左孩子,1 表示结点的前驱int rtag;      // 0表示结点的右孩子,1 表示结点的后继
};

树转化为二叉树

树转换为二叉树的规则:每个结点左指针指向他的第一个孩子结点,右指针指向它在树中的相邻兄弟结点,可以表示为 “左孩子右兄弟”

将树转换成二叉树的步骤是:

  1. 加线,就是在所有兄弟结点之间加一条连线;
  2. 去线,就是对树中的每个结点,只保留他与第一个孩子结点之间的连线,删除它与其它孩子结点之间的连线
  3. 调整,就是以树的根结点为轴心,将整棵树顺时针旋转一定角度,使之结构层次分明。

二叉树转换为树

二叉树转换为树是树转换为二叉树的逆过程,其步骤是:

  1. 若某结点的左孩子结点存在,将左孩子结点的右孩子结点、右孩子结点的右孩子结点……都作为该结点的孩子结点,将该结点与这些右孩子结点用线连接起来;
  2. 删除原二叉树中所有结点与其右孩子结点的连线;
  3. 整理步骤1和步骤2两步得到的树,使之结构层次分明。

森林转化为二叉树

森林是由若干棵树组成,可以将森林中的每棵树的根结点看作是兄弟,由于每棵树都可以转换为二叉树,所以森林也可以转换为二叉树。

将森林转换为二叉树的步骤是:

  1. 先把每棵树转换为二叉树;
  2. 第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子结点,用线连接起来。
  3. 当所有的二叉树连接起来后得到的二叉树就是由森林转换得到的二叉树。

二叉树转化为森林

二叉树转换为森林比较简单,其步骤如下:

  1. 先把每个结点与右孩子结点的连线删除,得到分离的二叉树;(二叉树→森林)
  2. 把分离后的每棵二叉树转换为树;(森林中的每棵树→二叉树)
  3. 整理步骤2得到的树,使之规范,这样得到森林。

二叉树连接起来后得到的二叉树就是由森林转换得到的二叉树。

【数据结构-树】2.二叉树遍历与线索二叉树(图解+代码)相关推荐

  1. 二叉树前序中序后续线索树_二叉树的先序,中序,后序遍历以及线索二叉树的遍历...

    二叉树的先序,中序,后序遍历以及线索二叉树的遍历 (2008-05-04 17:52:49) 标签: 杂谈 C++ 二叉树的先序,中序,后序遍历以及线索二叉树的遍历 头文件 //*********** ...

  2. 二叉树前序中序后续线索树_后序线索二叉树怎么画 线索二叉树基本操作详解 - 办公软件 - 服务器之家...

    后序线索二叉树怎么画 线索二叉树基本操作详解 发布时间:2017-05-23 来源:服务器之家 遍历二叉树是以一定规则将二叉树中结点排列成一个线性序列,得到二叉树中结点的先序,中序或后序序列.这实际上 ...

  3. 先序abdfcegh 中序bfdagehc 后序线索二叉树_二叉树的遍历和线索二叉树

    二叉树的遍历是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,且只被访问一次. 先序遍历(NLR) 若二叉树为空,则什么也不做:否则, (1)访问根结点. (2)先序遍历左子树. (3) ...

  4. 二叉树遍历(附Java实现代码)

    二叉树遍历(附Java实现代码) 二叉树遍历可以有两种方法:递归遍历的方式与非递归遍历的方式. 先序遍历就是先遍历根节点再左再右: 中序遍历就是先左再根再右: 后序遍历就是先左再右再根: 先构建这棵树 ...

  5. 二叉树遍历结果推二叉树_二叉树遍历(PreOrder,InOrder,PostOrder)

    二叉树遍历结果推二叉树 In this article, we shall look into how we can perform a Binary Tree Traversal using dif ...

  6. 二叉树遍历结果推二叉树_二叉树遍历技术

    二叉树遍历结果推二叉树 二叉树 (Binary Tree) A binary tree is a finite collection of elements or it can be said it ...

  7. 线索二叉树 C语言 数据结构 先序线索二叉树 中序线索二叉树 后序线索二叉树

    在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序.中序.后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化. 文章目录 一.c语言实现先序线索.中序线 ...

  8. 数据结构与算法(6-4)线索二叉树

    优势:便于在中序遍历下,查找前驱和后继. 前驱/后继含义:AB中,A是B前驱,B是A后继. ltag=0时:lchild指向左孩子                ltag=1时:lchild指向前驱 ...

  9. 数据结构-树与深度优先遍历

     笔者在读书时,选择的专业是计算机科学,但和大家一样,在处理线性的问题时较为熟悉,但当自己在尝试理解树和图这种非线性结构时,就总无法深刻准确的理解,为此,也很苦恼很无奈,但也没有什么好的办法.这次趁着 ...

最新文章

  1. django媒体文件上传设置
  2. 创建委托登录模块(用于JBoss EAP 6.1)
  3. Activiti工作流框架学习(一)环境的搭建和数据表的了解
  4. 大数据定制化服务需在成本和差异化间平衡
  5. Atom飞行手册翻译: 3.8 编写spec
  6. 想成为前端工程师,那么在大学期间应该如何规划?
  7. 数据结构与算法之美-队列
  8. Leetcode134.加油站
  9. 呼吁各行业实现无纸化办公
  10. 【Keil变量定义】定义extern类型变量
  11. margin-top传递问题
  12. 如何用idea比对代码差异
  13. 计算机系统变更注意事项,电脑更换cpu注意事项
  14. 根据身份证号或营业执照编号取省市区信息
  15. < CSDN话题挑战赛第1期 - 前端面试宝典 >
  16. 大数据方面的核心技术
  17. oracle的口令忘了_Oracle忘记用户名和密码的解决方案
  18. 制作京东快报页面html,仿京东快报.html
  19. 360手机n4s骁龙版 html,360 手机N4S(骁龙版/全网通)
  20. 网众linux无盘视频教程,网众无盘新手篇--LINUX系统网络安装

热门文章

  1. phoneGap异步加载JS失败
  2. 也许你不知道的c#基本数据类型及其默认值
  3. SQL Server中查询所有的表、视图、列和存储过程
  4. Windows MObile中ListView控件的用法详解
  5. 用C#语言构造蜘蛛程序
  6. AB1601的OTA区224K存储空间的使用注意事项
  7. ESP8266和MQTT
  8. PKI/CA (2)核心说明
  9. C++ Primer 5th笔记(7)chapter7 类:构造函数、类类型转换、聚合类
  10. 关于浮点数在计算机内存中的存储