树的理解
树是一种递归形式的调用
树是由于多个结点组成的有限集合T
树中有且仅有一个结点称为根
当结点大于1的时候,往往其余的结点为m个互不相交的有限个集合T1,…,Tm,每个互不相交的有限集合本身右是一棵树,称为这个根的子树
空树也是树
关于术语
根:根结点(没有前驱)
叶子:终端结点(没有后继)
森林:指的是m棵互不相交的树组成的集合(例如:删除R以后形成的A,B,C子树所形成的集合)
有序树:各结点子树从左向右有序,不能交换
无序树:各个结点之间可以互换位置
双亲:上层的那个结点(直接前驱parrrent)
孩子:下层结点的子树(直接后继child)
兄弟:同一个双亲下的同层结点(孩子直接互称兄弟)
堂兄弟:双亲位于同一层的简单(但是并非属于同一个双亲)
祖先:从根到该结点所经历的分支的所有结点
子孙:从该结点的下层子树中的任意结点
结点:树的数据元素
结点的度:结点挂接的子树数目(有几个后继就是几度,亦称为“次数”)----------->结点挂接的孩子有几个,度就是几
树的度:指的是所有结点,其中结点的孩子最多的(结点挂接子树最多的,就是树的度)(Max{各个结点的度})
结点的层次:从根到该结点的层数,根结点算作第一层
终端结点:及最后一层结点,度为0的结点,及叶子结点
分支结点:除了树根以外的结点(内部结点)
树的深度(树的高度):指的是所有结点中的最大的层数(Max{各结点的层次})(那这个不就相当于叶子结点到根结点的距离)
树的广义表示法
对于上图的树的广义表示法为:R(A(D,E),B,C(F(G,H,I)))
用途:
遵照左为尊,兄长如父的原则:
树的逻辑结构
一对多的关系(1:n),有多个直接后继,但是根结点只有一个,并且子树间互不相交。
树的存储结构
树是非线性结构,往往有顺序存储和链式存储等方式
如果将树的信息存储到数据库(首先将每一个结点的信息存入数据库)
往往将树存储到数据库中,首先定义一个结点表(存放每个结点)然后还需要定义一个结点关系表,用来存放结点之间的关系对于节点表以及结点关系表的定义如下:
二叉树
定义:二叉树是n个结点的有限集合,由一个根节点以及两颗互不相交的分别称为左子树和右子树的二叉树构成
逻辑的结构为:1:2
二叉树的基本特征:每个结点最多只有两棵子树(也就是说明了不存在度大于2的结点)
左子树和右子树的顺序不能颠倒(二叉树是一个有序树)
二叉树的性质
1)二叉树第二层的结点数最多为?
答:第二层结点最多为2i-1个结点。第i层上至少有1个结点
2)深度为k的二叉树,至多有几个结点?
答:至多有2k-1个结点。深度为k的二叉树至少有k个结点
3)对于任何一棵二叉树,若度为2的结点有N2个,则其叶子数必定为?
答:叶子数为N2+1个
满二叉树
一棵树的深度为K,并且有且仅有2k-1个结点的二叉树(特点:每层都充满了结点)
完全二叉树
深度为k的,有n个结点的二叉树,当且仅当其每一个结点斗鱼深度为k的满二叉树一一对应的结点。
第K-1层和满二叉树一样,在最后一层叶子结点尽量靠左
4)具有N个结点的完全二叉树它的深度为?
答:因为深度为K的完全二叉树它的结点数至多为2k-1,那么K等于⌊log2N⌋+1。其中**⌊⌋ **表示向下取整。
5):对于完全二叉树,若从上至下,从左至右编号,则编号为i的结点,其左孩子的编号必定为2i,其右孩子的编号必定为2i+1,其双亲的编号必为i/2(这里对应取整)
二叉树的存储结构
顺序存储:按照二叉树的结点“自上而下,自左至右”编号,用一组连续的存储单元存储
顺序存储后能否复原成唯一对应的二叉树的形状?
答:若是完全二叉树或者满二叉树则可以做到唯一复原。
而且复原是有规律的——下标为i的双亲,其左孩子的下标必定为2i,其右孩子的下标必定为2i+1
二叉树的链式存储
二叉链表示法
二叉链表示树:**往往树中的每个结点由三部分组成:数据域和左右指针域(如上图)**其左右指针域分别表示指向结点的左右孩子。
结点的数据类型定义如下:
#include<stdio.h>
#include<stdlib.h>
#pragma region 定义链表
typedef int DataType;
typedef struct Node
{
DataType data;//数据域
struct Node* next;//指针域Node表示这个链表的名字
}Node;
#pragma endregion
#pragma region 二叉链表示法
typedef struct BiTNode
{
DataType data;
struct BiTNode *lchild, *rchild;//左右孩子的结点指针
}BiTNode;
typedef BiTNode *BitTree;//用定义好的BitNode结点,再次定义*BitTree指针
/*数据域data存放结点的数据信息
lchild与rchild分别存储指向左孩子与右孩子的指针
当孩子结点不存在的时候,相应的指针指向NULL
*/
#pragma endregion
三叉链表示法
使用二叉链表示法虽然可以通过两个指针域便捷的找到孩子结点,但是无法直接便捷的寻找到当前结点的父结点。为了能够顺利的找到结点的父亲结点,可以以二叉链表的结点为基础,在结点中添加一个指向父结点的指针parent,形成一个带父亲结点指针的结点。这种节点构建出的二叉树其每个结点包括的成分为:数据域、左孩子指针域、右孩子指针域、父亲域
#pragma region 三叉链表示法
typedef struct BitNode
{
DataType data;
struct BitNode* lchild,* rchild;
struct BitNode* parent;
}BitNode,*BitTree;
#pragma endregion
memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。
void *memset(void *s, int c, size_t n);
s指向要填充的内存块。
c是要被设置的值。
n是要被设置该值的字符数。
返回类型是一个指向存储区s的指针。