数据结构--树(总结)

  • 树是一种非线性结构

树的定义

  • 有且只有一个称为根的节点
  • 有若干个互不相交的子树,这些子树本身也是一颗树
  • 深度:从根节点到最底层节点的层数称之为深度 根节点是第一层
  • 叶子节点:没有子节点的节点
  • 非终端节点:实际就是非叶子节点
  • :子节点的个数称为度

树的分类

  • 一般树:任何一个节点的子节点的个数都不受限制

  • 二叉树:任意一个子节点的个数最多两个,且子节点的位置不可更改

    1.满二叉树:在不增加树的层数的前提下,无法再多添加一个节点的二叉树就是满二叉树

    2.完全二叉树:如果只是删除了满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全二叉树

  • 森林:n个互不相交的树的集合

树的存储

二叉树的存储
连续存储(完全二叉树)
  • 优点:查找某个节点的父节点和子节点的速度很快
  • 缺点:耗用内存空间较大
链式存储
  • 结构体有两个指针域,一个指向它的左儿子,一个指向它的右儿子,如果没有值则赋为NULL
一般树的存储
  • 双亲表示法:在每个节点中 附设一个指示器指示其双亲结点到链表中的位置
//树的双亲表示法的结构体定义
#define MAX 100
typedef struct PTNode{
	int data;//结点数据
	int parent;//双亲位置
}PTNode;
typedef struct{		//树结构
	PTNode nodes[MAX];//结点数组
	int r,n;//根的位置和结点数
}PTree;
  • 孩子表示法:每个结点有多个指针域,其中每个指针指向一棵子树的根结点,我们把这种方法叫做多重链表表示法
    具体办法:把每个结点的孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果叶子结点则此单链表为空,然后n个头指针又成一个线性表,采用顺序存储结构,存放进一个一维数组中
//树的孩子表示法的结构体定义
#define MAX 100
typedef struct CTNode{      //孩子结点
	int child;
	int CTNode *next;
}*ChildPtr;
typedef struct{     //表头结构
	int data;
	ChildPtr firstchild;
}CTBox;
typedef struct{      //树结构
	CTBox nodes[MAX];//结点数组
	int r,n;//根的位置和结点数
}CTBox;
  • 孩子双亲表示法:前两种表示方法的结合,在表头结构中在加入一个双亲结点的结构体变量
  • 二叉树表示法:把一个普通的树转化成二叉树来存储,具体转换方法:左指针域指向它的第一个孩子,右指针域指向他的下一个兄弟 一个普通的树转化成的二叉树一定没有右子树

二叉树的定义与性质

  • 定义:二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成
  • 性质
    1.在二叉树的第i层上至多有2的i-1次方个结点
    2.深度为k的二叉树至多有2的k次方-1个结点
    3.对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。另外,如果n1为度是1的结点数,那么树T的总结点数n=n0+n1+n2
    4.具有n个结点的完全二叉树的深度为log以2为底的n的对数+1
    5.对于一颗有n个结点的完全二叉树的结点按层序编号,如果i=1,则为二叉树的根,双亲是[i/2],左节点是[i2],右节点是[i2+1].

二叉树的存储

1.顺序存储结构

  • 完全二叉树:用一组地址连续的存储单元 从上而下 从左到右(按层遍历) 存储完全二叉树的节点
  • 非完全二叉树:用一组地址连续的存储单元 从上而下 从左到右 (按层遍历)存储二叉树的节点;用“0”表示相应位置上不存在的节点

2.链式存储结构

  • 二叉链表节点 (lchild , data , rchild)、 三叉链表节点 (lchikd , data , parent , rchild) 链表的头指针指向根结点;
  • 在含有n个节点的二叉链表中 有n+1个空链域

二叉树的遍历

二叉树的遍历方法主要分为三种,前序遍历,中序遍历,后续遍历

1.先序遍历[先访问根节点]

… … …先访问根结点
… … …再先序访问左子树
… … …再先序访问右子树
在这里插入图片描述

//二叉树的前序遍历递归算法
void PreOrderTraverse(BiTree T){
	if(T==NULL)
		return;
	printf("%c",T->data);//显示结点数据  可更改为其他操作
	PreOrderTraverse(T->lchild);//先先序遍历左子树
	PreOrderTraverse(T->rchild);//最后先序遍历右子树
}

2.中序遍历[中间访问根节点]

… … …先中序遍历左子树
… … …再访问根结点
… … …再中序遍历右子树
在这里插入图片描述

//二叉树的中序遍历递归算法
void InOrderTraverse(BiTree T){
	if(T==NULL)
		return;
	InOrderTraverse(T->lchild);
	printf("%c",T->data);
	InOrderTraverse(T->rchild);
}

3.后序遍历[中间访问根节点]

… … …先中序遍历左子树
… … …再中序遍历右子树
… … …再访问根结点
在这里插入图片描述

//二叉树的后序遍历递归算法
void PostOrderTraverse(BiTree T){
	if(T==NULL)
		return;
	PostOrderTraverse(T->lchild);
	PostOrderTraverse(T->rchild);
	printf("%c",T->data);
}

注意:
已知数的先序遍历和后序遍历不能唯一的确定一颗树。

先序遍历+中序遍历=唯一确定一棵树;
后序遍历+中序遍历=唯一确定一颗树;

树、森林与二叉树的转换

  • 树转换为二叉树
    左儿子是它的第一个孩子,右儿子是他的一个兄弟
  • 森林转换为二叉树
    森林中的每一棵树都是兄弟,当成右孩子处理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值