文章目录
二叉树的链式结构
二叉树的存储结构有顺序结构和链式结构两种,顺序结构我已经在上篇进行了详细的讲解,地址:数据结构-二叉树的顺序存储与堆(堆排序),本篇我们就主要讲解二叉树的链式存储。
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,其结构如下图:
三叉链在后面讲解红黑树时再讲解,本篇我们主要先来以二叉链来学习一下二叉树的实现。
链式结构的遍历
我们知道二叉树的结构不是线性的,每一个节点都有两个子树,那如果我们想要访问一个二叉树中的所以元素时,我们应该以什么样的规律去访问呢,是先访问根节点还是先访问子树?这就涉及到了二叉树的遍历问题。
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
遍历顺序一共分为4种,分别是:
- NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。先根遍历
- LNR:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。中根遍历
- LRN:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。后根遍历
- 层序遍历:设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
简单来说,前,中,后序遍历就是以访问根节点的时间不同来划分的
前序:根->左子树->右子树
中序:左子树->根->右子树
后续:左子树->右子树->根
不同的遍历顺序有什么差异呢,比如我们现在想要遍历下面这个二叉树
我们可以发现不同的遍历顺序访问元素的顺序确实是不一样的。
二叉树的前,中,后序遍历属于深度优先的遍历方式,一般用递归实现。
层序遍历属于广度优先的遍历方式,一般借助队列实现。
他们的实现我就放在后面链式存储的实现中了。
二叉树链式存储的实现
在实现二叉树之前,我们要先创建一个二叉树节点的结构体类型,然后我们可以通过根节点对这个二叉树进行操作。
typedef char BTDataType;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left; // 指向当前节点左孩子
struct BinaryTreeNode* right; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
}BTNode;
二叉树节点的创建
BTNode* CreateTreeNode(BTDataType x)
{
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
1.动态开辟一个空间存放我们节点的值,把左右指针置空,返回节点的地址。
(该接口可以用来创建二叉树的所有节点)
前序遍历
根据根,左子树,右子树的顺序访问二叉树的所以值
void PrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
//根 左子树 右子树
printf("%c ", root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
1.先判断节点是否为空,空就返回。
2.前序遍历,先访问根节点,那就是节点当前的值,在访问左子树,再访问右子树,使用递归的方法实现。
大伙可以看下面的流程图来更好的理解前序遍历的递归过程
我们还是遍历上图中的哪个二叉树。
中序遍历
void InOrder(BTNode* root