当前位置: 首页 > article >正文

数据结构——树,二叉树

树:

树是⼀种非线性的数据结构,它是由 n(n>=0)个有限结点组成⼀个具有层次关系的集合。

树中有⼀个特殊的结点,称为根结点,根结点没有前驱结点。除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2、……、Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以 有 0 个或多个后继。因此,树是递归定义的。 树形结构中,子树之间不能有交集,否则就不是树形结构。

树中的相关术语:

⽗结点/双亲结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点;

⼦结点/孩⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点;

结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;

树的度:⼀棵树中,最⼤的结点的度称为树的度;

叶⼦结点/终端结点:度为 0 的结点称为叶结点;

分⽀结点/⾮终端结点:度不为 0 的结点;

兄弟结点:具有相同⽗结点的结点互称为兄弟结点(亲兄弟);

结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;

树的⾼度或深度:树中结点的最⼤层次;

结点的祖先:从根到该结点所经分⽀上的所有结点

路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列

⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。

森林:由 m(m>0) 棵互不相交的树的集合称为森林;

在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

二叉树:

在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

⼆叉树具备以下特点: 1. ⼆叉树不存在度⼤于 2 的结点 2. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树。

满二叉树: 

⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀ 个⼆叉树的层数为 K ,且结点总数是 2 ^ k  −  1 ,则它就是满⼆叉树。

完全二叉树:

完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个 结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 ⾄ n 的结点⼀⼀对应时称 之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。

二叉树的性质:

根据满⼆叉树的特点可知: 1)若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有      2 ^ (i−1) 个结点

2)若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 (2 ^ h)  -  1;

3)若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度为 \log_{2}(n+1)

二叉树的实现:

头文件 Tree.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef char BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

//根据前序遍历构建二叉树
BTNode* BinaryTreeCreate(char* tree, int* pi);

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

// 二叉树销毁
void BinaryTreeDestory(BTNode** root);

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

//二叉树深度
int BinaryTreeDepth(BTNode* root);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

源文件 Tree.c 

#include"Tree.h"
#include"queue.h"

BTNode* buyNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror(malloc);
		exit(1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}

BTNode* BinaryTreeCreate(char* tree, int* pi)
{
	if (tree[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = buyNode(tree[*pi]);
	(*pi)++;
	root->left = BinaryTreeCreate(tree, pi);
	root->right = BinaryTreeCreate(tree, pi);
	return root;
}

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c ", root->data);
	BinaryTreeInOrder(root->right);
}

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c ", root->data);
}

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QInit(&q);
	QPush(&q, root);
	while (!QEmpty(&q))
	{
		BTNode* top = QFront(&q);
		QPop(&q);
		printf("%c ", top->data);
		if (top->left)
			QPush(&q, top->left);
		if (top->right)
			QPush(&q, top->right);
	}

	QDestroy(&q);
}

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return BinaryTreeLeafSize(root->left) 
		+ BinaryTreeLeafSize(root->right);
}

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) +
		BinaryTreeLevelKSize(root->right, k - 1);
}

//二叉树深度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftd = BinaryTreeDepth(root->left);
	int rightd = BinaryTreeDepth(root->right);
	return 1 + (leftd > rightd ? leftd : rightd);
}

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* ret = BinaryTreeFind(root->left, x);
	if (ret)
		return ret;
	ret = BinaryTreeFind(root->right, x);
	if (ret)
		return ret;
	return NULL;
}

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QInit(&q);
	QPush(&q, root);
	while (!QEmpty(&q))
	{
		BTNode* top = QFront(&q);
		QPop(&q);
		if (top == NULL)
			break;
		QPush(&q, top->left);
		QPush(&q, top->right);
	}

	while (!QEmpty(&q))
	{
		BTNode* top = QFront(&q);
		QPop(&q);
		if (top)
		{
			QDestroy(&q);
			return false;
		}
	}
	QDestroy(&q);
	return true;
}

// 二叉树销毁
void BinaryTreeDestory(BTNode** proot)
{
	if (*proot == NULL)
		return;
	BinaryTreeDestory(&((*proot)->left));
	BinaryTreeDestory(&((*proot)->right));
	free(*proot);
	*proot = NULL;
}

二叉树的相关函数中大多使用了递归来定义,毕竟树结构也是通过递归来定义的。

二叉树的遍历:

二叉树的先序遍历:先遍历根节点,再遍历左儿子(若有),最后遍历右儿子(若有)。(根左右)
二叉树的中序遍历:先遍历左儿子(若有),再遍历根节点,最后遍历右儿子(若有)。(左根右)
二叉树的后序遍历:先遍历左儿子(若有),再遍历右儿子(若有),最后遍历根节点。 (左右根)

 当知道二叉树的前序遍历,后序遍历之一和中序遍历是就可以唯一确定一颗二叉树,但知道前序和后序是无法确定二叉树的。

由中序、后序、前序遍历得到二叉树的一半方法:

  1. 由前序或者后序确定根节点;
  2. 在中序遍历中找到根节点的左右子树所对应的区间;
  3. 再在左右子树中重复1,2过程,最终就可以得到一颗二叉树。


http://www.kler.cn/a/580142.html

相关文章:

  • 火语言RPA--PDF转Word
  • mysql的锁--一篇读懂所有锁机制
  • 微服务项目如何部署?
  • 截取一对中括号里面的内容
  • 深入解析K8s VolumeMounts中的subPath字段及其应用
  • Unity开发——CanvasGroup组件介绍和应用
  • Netty基础—1.网络编程基础一
  • Python助力区块链数据可视化:从数据到洞见
  • vue项目纯前端把PDF转成图片并下载
  • [250310] Mistral 发布世界领先的文档理解 API:Mistral OCR | 谷歌利用 AI 保护自然的三种新方式
  • 三星首款三折叠手机被曝外屏6.49英寸:折叠屏领域的新突破
  • DOM容器
  • 刷题记录(LeetCode 78 子集)
  • preact组件案例的使用
  • 常见HTTP 状态码及意义
  • Vue脚手架基础
  • 【Servlet】深入解析 Servlet 启动过程 —— 原理分析、代码实战及在 JDK 和 Spring 中的应用
  • Unity ES3保存类的问题
  • 单元测试、系统测试和集成测试知识总结
  • javaEE初阶————多线程进阶(2)