树和二叉树

目录

一 树的概念及结构

1.1树的概念及结构

1.2树的表示

二 二叉树的概念及结构

2.1基本概念

2.2特殊的二叉树

2.3二叉树性质 

2.4二叉树性质练习题

2.5顺序存储

 三 二叉树遍历

1 二叉树前中后序遍历

1.1基本概念

1.2前中后序代码实现

1.3递归画图理解

2 层序遍历

2.1基本思想

2.2代码实现

3 节点个数

3.1代码实现

4 叶子节点个数

4.1代码实现


一 树的概念及结构

1.1树的概念及结构

树是一种非线性的数据结构,它是由nn>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的

节点的度:一个节点含有的子树的个数称为该节点的度; 如下图: A 的为 6
叶节点或终端节点:度为 0 的节点称为叶节点; 如下图: B C H I... 等节点为叶节点
非终端节点或分支节点:度不为 0 的节点; 如下图: D E F G... 等节点为分支节点
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如下图: A B
的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如下图: B A 的孩子节
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如下图: B C 是兄弟节点
树的度:一棵树中,最大的节点的度称为树的度; 如下图:树的度为 6
节点的层次:从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推;
树的高度或深度:树中节点的最大层次; 如下图:树的高度为 4(根默认为1,也可以默认为0)
节点的祖先:从根到该节点所经分支上的所有节点;如下图: A 是所有节点的祖先
森林:由 m m>0 )棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是
一个森林)

1.2树的表示

树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式, 如:双亲表示法,孩子表示法、孩子兄弟表示法等等。我们这里就简单的了解其中最常用的孩子 兄弟表示法

二 二叉树的概念及结构

2.1基本概念

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子 树和右子树的二叉树组成。 (度不超过2的树)
二叉树的特点:
1. 每个结点最多有两棵子树,即二叉树不存在度大于 2 的结点。
2. 二叉树的子树有左右之分,其子树的次序不能颠倒。

2.2特殊的二叉树

2.3二叉树性质 

1. 若规定根节点的层数为 1 ,则一棵非空二叉树的 i 层上最多有 2^(i-1) 个结点 .
2. 若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是 2^h- 1 .
3. 对任何一棵二叉树 , 如果度为 0 其叶结点个数为 n0, 度为 2 的分支结点个数为 n2
则有 n0 n2 1
4. 若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度 h=LogN(由于格式问题具体见下图解)

2.4二叉树性质练习题

2.5顺序存储

顺序结构存储就是使用 数组来存储 ,一般使用数组 只适合表示完全二叉树 ,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

 三 二叉树遍历

1 二叉树前中后序遍历

1.1基本概念

所谓遍历 (Traversal) 是指沿着某条搜索路线, 依次对树中每个结点均做一次且仅做一次访问 。访问结点所做的操作依赖于具体的应用问题。遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
前序 / 中序 / 后序的递归结构遍历 :是根据访问结点操作发生位置命名
1. NLR :前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右(根  左子树  右子树)
子树之前。
2. LNR :中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中
(左子树  根  右子树)。
3. LRN :后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。
(左子树  右子树  根)
由于被访问的结点必是某子树的根, 所以 N(Node )、 L(Left subtree )和 R(Right subtree )又 可解释为根、根的左子树和根的右子树 NLR LNR LRN 分别又称为先根遍历、中根遍历和后根遍历。

1.2前中后序代码实现



//前序
void PrevOrder(Tree*root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%c ",root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}


//中序
void InOrder(Tree* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}

//后序
void PostOrder(Tree* root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);
}

1.3递归画图理解

2 层序遍历

2.1基本思想

层序遍历是利用队列的结构特点实现的

2.2代码实现

//层序遍历
void LevelOrder(Tree* root)
{
	Queue q;
	QueueInit(&q);

	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		Tree* Front = QueueFront(&q);
		QueuePop(&q);

		printf("%c ", Front->data);

		if (Front->left)
			QueuePush(&q, Front->left);
		if (Front->right)
			QueuePush(&q, Front->right);
	}
	printf("\n");
	QueueDestory(&q);
}

3 节点个数

3.1代码实现

//第一种
//使用全局变量
//缺点在多线程中同时计算两棵树的时候会有问题
int size1 = 0;
void TreeSize1(Tree* root)
{
	if (root == NULL)
		return;
	size1++;
	TreeSize1(root->left);
	TreeSize1(root->right);
}


//第二种
//传地址
void TreeSize2(Tree* root,int* psize)
{
	if (root == NULL)
		return;
	(*psize)++;
	TreeSize2(root->left,psize);
	TreeSize2(root->right,psize);
}

//第三种
//分治思想
int TreeSize3(Tree* root)
{
	return root == NULL ? 0 : TreeSize3(root->left) + TreeSize3(root->right) + 1;
}

4 叶子节点个数

4.1代码实现

// 叶子节点的个数
int TreeLeafSize(Tree* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left)+TreeLeafSize(root->right);
}

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值