K:二叉树
相关介绍:
二叉树是一种特殊的树,它的每个节点最多只有两棵子树,并且这两棵子树也是二叉树。由于二叉树中的两棵子树有左右之分,为此,二叉树是有序树。
二叉树的定义:
二叉树是由n(n>=0)个节点所以构成的有限集合。当n=0时,这个集合为空,此时的二叉树为空树;当n>0时,这个集合是由一个根节点和两个互不相交的分别称为左子树和右子树的二叉树所构成。
二叉树的存储结构:
二叉树的存储实现有多种方式,但是归纳起来主要分为顺序存储和链式存储两大类。下面用于介绍这两种存储方式:
顺序存储:
二叉树的顺序存储是指按照某种顺序依次将二叉树中的各个节点的值存放在一组地址连续的存储单元中。由于二叉树是非线性结构,所以需要将二叉树中的各个节点先按照一定的顺序排列成一个线性序列,再通过这些节点在线性序列中的相对位置,确定二叉树的各个节点之间的逻辑关系。对于一棵完全二叉树,我们可以从根节点开始自上而下并按照层次由左向右对节点依次进行编号,然后按照编号顺序依次将其存放在一维数组中。对于一棵非完全二叉树来说,可以先在此树中增加一些并不存在的虚节点并使其成为一棵完全二叉树,然后用与完全二叉树相同的方法对节点进行编号,再将编号为i的节点的值存放到数组下标为i的数组单元中,虚节点不存放任何值。如下图1.1所示

注意点:对于满二叉树和完全二叉树来说,顺序存储是一种最简单,最节省空间的存储方式,而且其操作简单,所以顺序存储方式非常适用于满二叉树和完全二叉树。但对于非完全二叉树,由于“虚节点”的存在从而造成了存储空间的浪费。
链式存储:
二叉树的链式存储是指将二叉树的各个节点随机的存放在位置任意的内存空间中,各个节点之间的逻辑关系通过指针来反映,由于二叉树中的任意一个节点至多只有一个双亲节点和两个孩子节点,所以在用链式存储方式来实现二叉树的存储时,可以有两种方式,一种是二叉链表存储结构;一种是三叉链表存储结构。在二叉链表结构中,二叉树中的每个节点设置有三个域,一个数据域,左孩子域和右孩子域。其中,数据域用来存放节点的值。左右孩子域分别用来存放该节点的左、右孩子节点的存储地址。三叉链表结构是指在二叉链表结构的基础上增加了一个父节点域,该域用来存放此节点的父节点的存储地址。三叉链式存储结构既便于查找孩子节点,又便于查找双亲节点,当它相对二叉链表存储结构来说,增加了存储空间的开销。因此,在实际应用中,二叉链表结构是二叉树最为常用的存储结构。图1.2和图1.3演示了三叉链表存储结构和二叉链表存储结构


需要注意的是:二叉树的存储结构中,有分带头节点和不带头节点的这两种情况,带头节点的二叉树,其头节点不存储任何数据,而不带头节点的二叉树,其第一个节点便存储相关的数据。为方便起见,以下的代码演示的均是不带头节点的情况
相关代码:
三叉链表存储结构的节点描述:
class Node
{
//用于记录双亲节点的指针
Node parent;
//用于记录左孩子的指针
Node left;
//用于记录右孩子的指针
Node right;
//用于记录节点数据的对象指针
T data;
}
二叉链表存储结构的节点描述:
class Node
{
//用于记录左孩子的指针
Node left;
//用于记录右孩子的指针
Node right;
//用于记录节点数据的对象指针
T data;
}
二叉链表存储结构下的二叉树类的描述:
package all_in_tree;
/**
* 该类用于演示二叉树的情况
* @author 学徒
*
*/
public class BinaryTree
{
class Node
{
//用于记录左孩子的指针
Node left;
//用于记录右孩子的指针
Node right;
//用于记录节点数据的对象指针
Object data;
public Node(Object data)
{
this(data,null,null);
}
public Node(Object data,Node left,Node right)
{
this.data=data;
this.left=left;
this.right=right;
}
}
//根节点的对象
private Node root;
//用于创建一棵空树
public BinaryTree()
{
root=null;
}
//用于创建一棵一某个节点为根节点的树
public BinaryTree(Node root)
{
this.root=root;
}
/**
* 根据先根遍历和中根遍历的序列创建一棵二叉树
* @param preOrder 先序遍历的序列
* @param inOrder 中序遍历的序列
* @param preIndex 先序遍历中根节点所在的序列
* @param inIndex 中序遍历中根节点所在的序列
* @param count 子树序列的长度
* 其步骤如下:
* 1. 先判断先/中序遍历序列是否为空
* 2. 找到其对应的根节点
* 3. 找根节点在中序遍历序列中的位置
* 4. 建立根节点
* 5. 建立左右子树
*/
public BinaryTree(String preOrder,String inOrder,int preIndex,int inIndex,int count)
{
if(count>0)
{
char r=preOrder.charAt(preIndex);
int i=0;
for(;i<count;i++)
{
if(r==inOrder.charAt(inIndex+i))
break;
}
root =new Node(r);
root.left=(new BinaryTree(preOrder,inOrder,preIndex+1,inIndex+1,i)).root;
root.right=(new BinaryTree(preOrder,inOrder,preIndex+i+1,inIndex+i+1,count-i-1)).root;
}
}
}
二叉树的基本操作:
对于二叉树,其遍历操作为其基本的操作。遍历的方式有四种,分别为层次遍历、先序遍历、中序遍历、后序遍历,下面将分别介绍这四种遍历方式
层次遍历:
对于层次遍历,其按照的是的各个节点在树中所处的层次顺序进行遍历的。其操作步骤为,先访问第0层的根节点,然后从左到右依次访问第1层的每一个节点,依次类推,当第i层上的所有节点都访问完后,再从左往右依次访问第i+1层的每一个节点,知道最后一层的所有节点都访问完为止。为此,为实现二叉树的层次遍历,应当使用一个队列依次沿着树的访问记录下其相关节点的孩子节点。其相关代码如下:
相关代码:
private static Queue<Node> q=new LinkedList<Node>();
public static void greed(Node root)
{
if(root!=null)
q.add(root);
while(!q.isEmpty())
{
Node node=q.poll();
//遍历其相关的节点的数据
System.out.print(node.data+" ");
if(node.left!=null)
q.add(node.left);
if(node.right!=null)
q.add(node.right);
}
}
先序遍历:
所谓的先序遍历,是指先访问其根节点后递归的依次访问其左子树和右子树的方式,其递归遍历方式的相关代码如下:
相关代码:
public void preRoot(Node root)
{
if(root!=null)
{
System.out.print(root.data+" ");
preRoot(root.left);
preRoot(root.right);
}
}
中序遍历:
所谓的中序遍历,是指先访问其左子树,然后访问其根节点,之后再访问其右子树的一种遍历方式,其递归遍历方式的相关代码如下:
public void inRoot(Node root)
{
if(root!=null)
{
inRoot(root.left);
System.out.print(root.data+" ");
inRoot(root.right);
}
}
后序遍历:
所谓的后序遍历,是指先访问其左子树,让后再访问其右子树,最后在访问其根节点的一种遍历方式,其递归遍历方式的相关代码如下:
public void postRoot(Node root)
{
if(root!=null)
{
postRoot(root.left);
postRoot(root.right);
System.out.print(root.data+" ");
}
}
对于以上四种遍历方式中,其先序、中序、后序遍历方式可以采用非递归的方式,其非递归遍历方式的实现,参看博文 K:二叉树的非递归遍历
K:二叉树的更多相关文章
- Python数据结构——二叉树
数的特征和定义: 树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都 ...
- 二叉树的详细实现 (C++)
二叉树的定义 以递归形式给出的:一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的.互不相交的二叉树组成.二又树的特点是每个结点最多有两个子女, ...
- Python学习路程day17
常用算法与设计模式 选择排序 时间复杂度 二.计算方法 1.一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道.但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费 ...
- Python之路,Day21 - 常用算法学习
Python之路,Day21 - 常用算法学习 本节内容 算法定义 时间复杂度 空间复杂度 常用算法实例 1.算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的 ...
- Python之路:常用算法与设计模式
选择排序 时间复杂度 二.计算方法 1.一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道.但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花 ...
- python 常用算法学习(2)
一,算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时间内获得所要求 ...
- 第四百一十五节,python常用排序算法学习
第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...
- 4.python字符串格式化
格式化字符串时,Python使用一个字符串作为模板.模板中有格式符,这些格式符为真实值预留位置,并说明真实数值应该呈现的格式.Python用一个tuple将多个值传递给模板,每个值对应一个格式符.py ...
- 用Python实现数据结构之二叉搜索树
二叉搜索树 二叉搜索树是一种特殊的二叉树,它的特点是: 对于任意一个节点p,存储在p的左子树的中的所有节点中的值都小于p中的值 对于任意一个节点p,存储在p的右子树的中的所有节点中的值都大于p中的值 ...
- TZOJ 数据结构期末历年题目
A.数据结构练习题――线性表操作 线性表的基本操作 1.在某个位置p插入val,复杂度O(p) 2.在某个位置p删除val,复杂度O(p) 3.查找某个位置p的值,复杂度O(p) 4.清除链表,复杂度 ...
随机推荐
- 动态规划-迷宫-百度之星-Labyrinth
Labyrinth Problem Description 度度熊是一仅仅喜欢探险的熊.一次偶然落进了一个m*n矩阵的迷宫,该迷宫仅仅能从矩阵左上角第一个方格開始走,仅仅有走到右上角的第一个格子才算走 ...
- java 单例模式学习笔记
1.单例模式概述 单例模式就是确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供. 2.优缺点 优点:在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模 ...
- 数据库、ArcCatalog空间数据源正常访问,数据库设置没问题时,ArcEngine连接SDE时报"ORA-12560: TNS: 协议适配器错误"的解决办法;ArcEngine连接SDE总结
碰到的问题描述: 通过C# 基于ArcEngine写SDE直连的时候测试项目连接属性设置为如下: tPropSet.SetProperty("User", "GISDAT ...
- idea 导入项目后 有的项目目录结构不展开解决办法
如图:可能会出现这中国情况. 解决办法: 1.一般项目导入完成后,但是目录不展开, 2.出现这种情况一般情况下, 关闭idea close idea ,然后重新导入一遍就OK.
- jsp中EL表达式不起作用的问题1
问题:在jsp页面中使用el表达式取值,取不到值,但是使用jsp中嵌套java代码可以取到值,对应代码如下: 解决: 只要在 jsp中 头文件中写上 : <%@page isELIgnored= ...
- MVC+EF 入门教程(二)
一.前沿 为了使以后项目分开,所以我会添加3个类库.用于存储 实体.数据库迁移.服务.这种思路是源于我使用的一个框架 ABP.有兴趣的您,可以去研究和使用这个框架. 二.修改本地连接 在项目中,找到 ...
- 判断DataTable某一列是否是时间列
DataTable dt = new DataTable("Table0"); dt.Columns.Add("column0", System.Type.Ge ...
- C#Lambda表达式Aggregate的用法及内部运行方式的猜想
, , , , }; // 其和为15 var count = nums.Aggregate((body, next) => { // 注意,nums的元素个数至少一个以上(但如果是有seed的 ...
- 使用VSCode创建Asp.Net Core
前言 .Net Core 2.0已经发布几个月了,惭愧!身为一个开发人员现在才开始接触,有人说有VS这一宇宙第一IDE在,为啥还要用VSCode,为啥?因为我们是程序猿啊!我们是攻城狮啊!我们爱折腾啊 ...
- Cat 客户端如何构建调用链消息树
场景 & 代码 Inner0 中的某方法调用了 Inner1,代码 Inner1的代码很简单, Cat通过一个线程本地变量来保存调用链的相关信息,其中核心的数据结构是消息树和操作栈.消息树用来 ...