【数据结构与算法】two X 树的遍历以及功能实现(上)

简介: 【数据结构与算法】two X 树的遍历以及功能实现(上)

前言:

       前面我们已经提到过树、二叉树的概念及结构、堆排序、Top-k问题等的知识点,这篇文章我们来详解一下二叉树的链式结构等问题。

💥🎈个人主页:Dream_Chaser~ 🎈💥

✨✨专栏:http://t.csdn.cn/oXkBa

⛳⛳本篇内容:c语言数据结构--二叉树的遍历以及功能实现

869b18be53c8456bad658703cc0743cb.gif


一.链式二叉树存储的概念


       二叉树的链式存储结构是指: 用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。

       通常的方法是链表中每个结点由三个域组成, 数据域和左右指针域,左右指针分别用来给出该结点 左孩子和右孩子所在的链结点的存储地址

链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面课程学到高阶数据结构如红黑树等会用到三叉链。

084abc567528432199110fb0a56634d1.png


二.链式二叉树结构的实现


2.1 前置说明

       在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。

 由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,

       此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

typedef int BTDataType;
typedef struct BinaryTreeNode
{
  BTDataType data;
  struct BinaryTreeNode* left;
  struct BinaryTreeNode* right;
}BTNode;
BTNode* BuyNode(BTDataType x)
{
  BTNode* node = (BTNode*)malloc(sizeof(BTNode));
  if (node == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  node->data = x;
  node->left = NULL;
  node->right = NULL;
  return node;
}
BTNode* CreatBinaryTree()
{
  BTNode* node1 = BuyNode(1);
  BTNode* node2 = BuyNode(2);
  BTNode* node3 = BuyNode(3);
  BTNode* node4 = BuyNode(4);
  BTNode* node5 = BuyNode(5);
  BTNode* node6 = BuyNode(6);
  node1->left = node2;
  node1->right = node4;
  node2->left = node3;
  node4->left = node5;
  node4->right = node6;
  return node1;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

再看二叉树基本操作前,再回顾下二叉树的概念, 二叉树是:

1. 空树

2. 非空:根节点,根节点的左子树、根节点的右子树组成的。

6b8f3a307d754466b18ff162814538ba.png

     从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。


2.2二叉树的遍历

    学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作, 并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

98b83288d70e465aa9e89b1d5809647e.png

以先序遍历为例子:

c9b9eb4310b043ba91bb4ef2b628eb36.png


前序遍历(Preorder Traversal)

       亦称先序遍历,访问根结点的操作发生在遍历其左右子树之前.

525d042a2b5946779591d7a192f7c5ac.png

中序遍历(Inorder Traversal)

访问根结点的操作发生在遍历其左右子树之中(间)

fe55a37a15254785bd98cdce26eb3e2f.png


后续遍历(Postorder Traversal)

访问根结点的操作发生在遍历其左右子树之后.

bfa9692bb0234dc5a6df118f42fef2c3.png

 由于被访问的结点必是某子树的根, 所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历


层序遍历(LevelOrder)

层序遍历 : 除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

1c29a1fe85f94565b64ffcd98407429a.png


2.3二叉树功能的实现

二叉树结构定义(struct BinaryTreeNode)

代码实现:

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


二叉树节点的创建(CreatBinaryTree)
BTNode* BuyNode(BTDataType x)//树中一个节点的创建
{
  BTNode* node = (BTNode*)malloc(sizeof(BTNode));
  if (node == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  node->data = x;
  node->left = NULL;
  node->right = NULL;
  return node;
}
BTNode* CreatBinaryTree()//树的构造
{
  BTNode* node1 = BuyNode(1);
  BTNode* node2 = BuyNode(2);
  BTNode* node3 = BuyNode(3);
  BTNode* node4 = BuyNode(4);
  BTNode* node5 = BuyNode(5);
  BTNode* node6 = BuyNode(6);
  node1->left = node2;
  node1->right = node4;
  node2->left = node3;
  node4->left = node5;
  node4->right = node6;
  return node1;
}


二叉树的前序遍历函数(PrevOrder)

       递归不可能一直调用函数,因为这个过程一直在创建栈帧,即使栈再大,也会栈溢出。所以肯定会回归,回归的本质就是销毁栈帧。

递归是由两个部分构成:

1.子问题

2.返回条件

图解:

40778ff82a654e4886a9484ee201512b.png

7d6e38550fc74fcd994c07474791e772.png

代码实现:

void PrevOrder(BTNode* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  printf("%d ", root->data);
  PrevOrder(root->left);
  PrevOrder(root->right);
}


二叉树的中序遍历函数(InOrder)

绘图:

b35c54a1ec7d4d4f8d539abc3e8373fe.png

void InOrder(BTNode* root) 
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  InOrder(root->left);
  printf("%d ", root->data);
  InOrder(root->right);
}
二叉树的后序遍历函数(PostOrder)

       跟前中序的思路相差不大,这里就不绘图了。

代码实现:

void PostOrder(BTNode* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  PostOrder(root->left);
  PostOrder(root->right);
  printf("%d ", root->data);
}


统计二叉树节点个数(BTreeSize)

画出递归展开图:

b0ed7f46891b41118dcf5066239038c2.png

int BTreeSize(BTNode* root)
{
  //写法一
  if (root == NULL)
    return 0;
  return BTreeSize(root->left) + BTreeSize(root->right) + 1;
  //写法二
  return root == NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}
求出叶子节点的数量(BTreeLeafSize)

a8627ab6306941aa9b28a83aed725343.png

     进入函数首先判断根节点是否为空,为空就直接返回0,说明树为空,直接返回叶子节点数量为0。


       接下来,检查当前的节点是叶子节点还是分支节点,若代码检查当前节点是否为叶子节点,即该节点的左子节点和右子节点都为空。如果是叶子节点,返回叶子节点数量为1。


       如果当前节点为分支节点,则继续调用该函数,计算左子树和右子树的叶子节点数量,并将它们相加,得到当前节点为根的子树的叶子节点数量。

最后,函数返回左子树和右子树叶子节点数量的和,即整个二叉树的叶子节点数量。

int BTreeLeafSize(BTNode* root)//接受一个指向二叉树节点的指针root作为参数
{
  if (root == NULL)//代码检查根节点是否为空
  {
    return 0;
  }
  if ( root->left==NULL &&root->right==NULL)
  {
    return 1;
  }
  return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}


相关文章
|
1天前
|
机器学习/深度学习 算法 搜索推荐
R语言LASSO特征选择、决策树CART算法和CHAID算法电商网站购物行为预测分析
R语言LASSO特征选择、决策树CART算法和CHAID算法电商网站购物行为预测分析
|
2天前
|
机器学习/深度学习 数据采集 算法
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
10 1
|
2天前
|
存储 算法
【数据结构与算法】8.二叉树的基本概念|前序遍历|中序遍历|后序遍历
【数据结构与算法】8.二叉树的基本概念|前序遍历|中序遍历|后序遍历
|
4天前
|
算法
数据结构与算法-AVL树入门
数据结构与算法-AVL树入门
8 0
|
4天前
|
算法
数据结构与算法-Trie树添加与搜索
数据结构与算法-Trie树添加与搜索
5 0
|
4天前
|
机器学习/深度学习 数据采集 算法
共享单车需求量数据用CART决策树、随机森林以及XGBOOST算法登记分类及影响因素分析
共享单车需求量数据用CART决策树、随机森林以及XGBOOST算法登记分类及影响因素分析
11 0
|
6天前
|
机器学习/深度学习 算法 数据挖掘
数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病
数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病
20 6
|
22天前
|
消息中间件 存储 搜索推荐
深入理解栈和队列(二):队列
深入理解栈和队列(二):队列
35 0
|
2月前
【栈】数据结构栈的实现
【栈】数据结构栈的实现
|
2月前
|
存储
数据结构--栈和队列
数据结构--栈和队列