c++数据结构:树(概念一)

树是n(n>=0)个节点的有限集。 

树的特点:

  • 有且仅有一个特定的根节点
  • 当n>0时,其余节点可分为m(m>0)个不相交的有限集N1,N2....Nn,其中每个集合本身又是一棵树,叫做子树。 
  • n=0时,为空树

 树的表示方法:

  1. 树形表示
  2. 嵌套表示
  3. 广义表表示
  4. 凹入表示法

 树的常用术语:

  • 树的结点包含一个数据元素及若干个指向其子树的分支
  • 节点拥有的子树称为节点的
  • 度为0的节点称为:叶子终端节点
  • 度不为0的节点称为:非终端节点或分支节点
  • 树的度:树内节点的度的最大值
  • 层次:从根开始定义,根为第一层,根的孩子为第二层
  • 深度和高度:树中节点的最大层次
  • 有序树和无序树:左右节点是有次序的(不能交换)是有序树,反之是无序树。

  •  A的度为3,B的度为2,c的度为1
  • K L M I J 为叶子,度为0
  • 树的度为:3(3为树内最大的度)
  • 树的深度为:4

 森林:

森林是m棵互不相交的树的集合,对树中每一个节点而言,其子树的集合为森林。

树一定是森林,森林不一定为树。

树和森林的区别: 

树只有一个根节点,森林可以有多个根节点。

 二叉树:

二叉树:节点至多有两颗子树(不存在度大于2的节点),二叉树的子树有左右之分,次序不能颠倒,二叉树也可以为空树。

二叉树的5种基本形态:

 二叉树的性质:

  • 二叉树的第i层最多有:     2^(i-1)   个节点(i>=1)
  • 深度为K的二叉树最多有:2^K-1    个节点(K>=1)
  • 对任意一颗二叉树T,其终端节点为N0,度为2的节点个数为N2,则N0=N2+1。
  • 具有n个节点的完全二叉树的深度为 log2(n)+1

 二叉树的特殊形态:

  • 满二叉树:深度为k,且有 2^(i-1) 个节点的二叉树
  • 完全二叉树:深度为k,有n个节点的二叉树,仅当其每一个节点都与深度为k的满二叉树中的节点位置一 一对应。叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部
  • 满二叉树是完全二叉树的特殊形态

已知节点数求二叉树的种类:

  • 使用卡特兰数:n为节点个数

 

 二叉树的存储结构:

顺序存储:

用一个数组进行存储,不存在的节点置为0。

#define Max_Size 100//二叉树的最大节点数
template<class T>
class tree
{
private:
	T tree[Max_size];//节点数组
};

这种方法只适用于完全二叉树,非完全二叉树的话空间浪费严重。

深度为k且只有k个节点的单支树需要2^k-1的一维数组。

 链式存储:

 节点的结构为:

  • 第一种:不需要parent指针(二叉链表)
  • 第二种:   需要parenr指针(三叉链表)

二叉链表:

template<class T>
class tree_node
{
private:
	T _data;//数据
	tree_node<T>* _leftchild;//左孩子指针
	tree_node<T>* _rightchild;//右孩子指针
};

三叉链表:

template<class T>
class tree_node
{
private:
	T _data;//数据
	tree_node<T>* _leftchild;//左孩子指针
	tree_node<T>* _rightchild;//右孩子指针
	tree_node<T>* _parent;//父类指针
};

两种的表示方法的示意图:

n个节点的二叉链表拥有n+1个空链域

n个节点的二叉链表用到的链域为n-1个(除了根节点)

三叉链表同理:用到的链域为:2*(n-1)     空链域为:n+2=3n-  2*(n-1) 

 遍历二叉树:

  • 先序遍历:                            
    1. 根节点
    2. 先序遍历左子树
    3. 先序遍历右子树
  • 中序遍历:
    1. 中序遍历左子树
    2. 根节点
    3. 中序遍历右子树
  • 后序遍历:
    1. 后序遍历左子树
    2. 后序遍历右子树
    3. 根节点
  • 层次遍历:从上到下,从左到右访问。
  • 已知前序遍历和中序遍历,可以确定一棵二叉树
  • 已知中序遍历和后序遍历,可以确定一棵二叉树
  • 已知前序遍历和后序遍历,无法确定一棵二叉树

先序遍历:

void travPre_R(binTree* BT)//先序遍历
{
	if (BT)//结点不为空
	{
		printf("%c", BT->data);//输出根节点
		travPre_R(BT->leftchild);//遍历左子树
		travPre_R(BT->rightchild);//遍历右子树
	}
}

中序遍历:

void travPre_R(binTree* BT)//中序遍历
{
	if (BT)//结点不为空
	{
		travPre_R(BT->leftchild);//遍历左子树
        printf("%c", BT->data);//输出根节点
		travPre_R(BT->rightchild);//遍历右子树
	}
}

后序遍历:

​
void travPre_R(binTree* BT)//后序遍历
{
	if (BT)//结点不为空
	{
		travPre_R(BT->leftchild);//遍历左子树
		travPre_R(BT->rightchild);//遍历右子树
        printf("%c", BT->data);//输出根节点
	}
}

线索二叉树:

在二叉树的结点上加上线索的二叉树。

如果某个节点的左孩子为空,将空的左孩子指针域改为指向其前驱,如果某个节点的右孩子为空,将空的右孩子指针域改为其后继,这种指向的指针称为线索

线索二叉树:加上线索的二叉树

线索二叉树的前中后序的画法:

  1. 按照你选择的遍历顺序找到相应节点的前驱和后继,
  2. 把为空的左孩子指向它的前驱
  3. 把为空的右孩子指向它的后继
  4. 没有前驱或后继为nullptr

节点结构为:

enum P{Link,Thead} 
class treenode
{
private:
	int data;
	treenode* lchild,*rchild;
	P LTag,RTag;左右标记
};

线索链表:由以上节点所构成的二叉链表作为二叉链表的存储结构

以下列举:前序遍历的示意图,中序和后序的类似就不列举了 。

 ,,,,,,,,,,,,,

优点:

  1. 利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间。
  2. 任意一个结点都能直接找到它的前驱和后继结点。

不足:

  1. 结点的插入和删除麻烦,且速度也较慢。
  2. 线索子树不能共用。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值