深入理解数据结构第三弹——二叉树(3)——二叉树的基本结构与操作

简介: 深入理解数据结构第三弹——二叉树(3)——二叉树的基本结构与操作

前言:

在前面我们讲了堆及其应用,帮助我们初步了解了二叉树的一些原理,但那与真正的二叉树仍有不同,今天我们就来正式学习一下二叉树的基本结构及其基本操作


一、什么是二叉树?

在前面的文章中我们已经提到过二叉树的结构及其特点,这里我们不过多赘述,有不理解的可以点文章开头的链接去前面看一下

二、二叉树的节点结构

二叉树有左右子树之分,且二叉树与我们所学的其他数据结构不同的点在于,之前我们所学的都是各类插入或者删除等等,但是二叉树需要做的操作是运用递归遍历,所以二叉树的节点结构与之前几个有很大不同

typedef int TreeDataType;
typedef struct Tree
{
  TreeDataType a;
  struct Tree* left;
  struct Tree* right;
}Tree;

节点结构里面定义有两个递归,是为了方便后面的遍历

三、二叉树的遍历

二叉树的遍历是我们学习二叉树首先要了解的东西,我们都知道二叉树其实就是一串数组,那我们是如何访问他们的呢?这里就牵扯到了遍历顺序的问题。

二叉树的遍历有三种形式:前序、中序和后序

  1. 前序遍历:
  • 特点:按照“根-左-右”的顺序遍历二叉树。
  • 特点:首先访问根节点,然后递归地前序遍历左子树,最后递归地前序遍历右子树。
  • 应用:常用于复制一棵树、计算表达式的值等。

中序遍历:

  • 特点:按照“左-根-右”的顺序遍历二叉树。
  • 特点:先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。
  • 应用:常用于二叉搜索树,可以得到一个递增的有序序列。

后序遍历:

  • 特点:按照“左-右-根”的顺序遍历二叉树。
  • 特点:先递归地后序遍历左子树,然后递归地后序遍历右子树,最后访问根节点。
  • 应用:常用于释放二叉树的内存空间,或者计算表达式的值。
  1. 例如:

四、二叉树的基本操作

我先把主函数给出,接下来就将按照主函数中的这些功能一步一步来实现

int main()
{
  Tree* root = CreatTree();
  //前序
  printf("前序:");
  PrevTree(root);
  printf("\n");
  //中序
  printf("中序:");
  HalfTree(root);
  printf("\n");
  //后序
  printf("后序:");
  PostTree(root);
  printf("\n");
  //节点个数
  int count = BTreeSize(root);
  printf("BTreeSize:%d\n", count);
  //叶子节点个数
  printf("BTreeLeafSize:%d\n", BTreeLeafSize(root));
  //树的高度
  printf("BTreeHigh:%d\n", BTreeHigh(root));
  //二叉树第k层节点个数
  printf("BTreeLevelKSize:%d\n", BTreeLevelKSize(root, 3));
  //二叉树查找值为x的节点
  
 
    return 0;
}

1、创建二叉树

//二叉树
typedef int TreeDataType;
typedef struct Tree
{
  TreeDataType a;
  struct Tree* left;
  struct Tree* right;
}Tree;
//初始化二叉树
Tree* TreeInit(TreeDataType x)
{
  Tree* m = (Tree*)malloc(sizeof(Tree));
  if (m == NULL)
  {
    perror("TreeInit");
    return NULL;
  }
  m->a = x;
  m->left = NULL;
  m->right = NULL;
  return m;
}
//创建一个二叉树
Tree* CreatTree()
{
  Tree* n1 = TreeInit(3);
  Tree* n2 = TreeInit(5);
  Tree* n3 = TreeInit(6);
  Tree* n4 = TreeInit(7);
  Tree* n5 = TreeInit(9);
 
  n1->left = n2;
  n1->right = n3;
  n2->left = n4;
  n2->right = n5;
 
  return n1;
}

2、前序、中序、后序

前序、中序和后序其实就是数据按照上面图片中的形式进行遍历

//前序
void PrevTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  printf("%d ", root->a);
  PrevTree(root->left);
  PrevTree(root->right);
}
//中序
void HalfTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  HalfTree(root->left);
  printf("%d ", root->a);
  HalfTree(root->right);
}
//后序
void PostTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  PostTree(root->left);
  PostTree(root->right);
  printf("%d ", root->a);
}

运行结果:

3、求二叉树的节点个数

//二叉树节点个数
int BTreeSize(Tree* root)
{
  //分治的思想
  if (root == NULL)
  {
    return 0;
  }
  return BTreeSize(root->left) + BTreeSize(root->right)+1 ;
}

用到了递归的思想,下面的内容都要用递归来解决,如果递归学的不太好建议画图来看这些过程如何进行的

运行结果:

4、求二叉树叶子节点的个数

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

运行结果:

5、树的高度

//求二叉树高度
int BTreeHigh(Tree* root)
{
  if (root == NULL)
  {
    return 0;
  }
  int leftHigh = BTreeHigh(root->left);
  int rightHigh = BTreeHigh(root->right);
 
  return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}

运行结果:

6、二叉树第k层的节点个数

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

运行结果:

7、二叉树查找值为x的节点

//二叉树查找值为x的节点
Tree* BTreeFind(Tree* root,int x)
{
  if (root == NULL)
    return NULL;
  if (root->a == x)
    return root;
  Tree* ret1 = BTreeFind(root->left, x);
  if (ret1)
  {
    return ret1;
  }
  Tree* ret2 = BTreeFind(root->right, x);
  if (ret2)
  {
    return ret2;
  }
}

五、完整代码实例

//二叉树
typedef int TreeDataType;
typedef struct Tree
{
  TreeDataType a;
  struct Tree* left;
  struct Tree* right;
}Tree;
//初始化二叉树
Tree* TreeInit(TreeDataType x)
{
  Tree* m = (Tree*)malloc(sizeof(Tree));
  if (m == NULL)
  {
    perror("TreeInit");
    return NULL;
  }
  m->a = x;
  m->left = NULL;
  m->right = NULL;
  return m;
}
//创建一个二叉树
Tree* CreatTree()
{
  Tree* n1 = TreeInit(3);
  Tree* n2 = TreeInit(5);
  Tree* n3 = TreeInit(6);
  Tree* n4 = TreeInit(7);
  Tree* n5 = TreeInit(9);
 
  n1->left = n2;
  n1->right = n3;
  n2->left = n4;
  n2->right = n5;
 
  return n1;
}
//前序
void PrevTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  printf("%d ", root->a);
  PrevTree(root->left);
  PrevTree(root->right);
}
//中序
void HalfTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  HalfTree(root->left);
  printf("%d ", root->a);
  HalfTree(root->right);
}
//后序
void PostTree(Tree* root)
{
  if (root == NULL)
  {
    printf("N ");
    return;
  }
  PostTree(root->left);
  PostTree(root->right);
  printf("%d ", root->a);
}
//二叉树节点个数
int BTreeSize(Tree* root)
{
  //分治的思想
  if (root == NULL)
  {
    return 0;
  }
  return BTreeSize(root->left) + BTreeSize(root->right)+1 ;
}
//二叉树叶子节点个数
int BTreeLeafSize(Tree* root)
{
  if (root == NULL)
  {
    return 0;
  }
  if (root->left == NULL && root->right == NULL)
  {
    return 1;
  }
  return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}
//求二叉树高度
int BTreeHigh(Tree* root)
{
  if (root == NULL)
  {
    return 0;
  }
  int leftHigh = BTreeHigh(root->left);
  int rightHigh = BTreeHigh(root->right);
 
  return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}
//二叉树第k层节点个数
int BTreeLevelKSize(Tree* root, int k)
{
  assert(k > 0);
  if (root == NULL)
  {
    return 0;
  }
  if (k == 1)
  {
    return 1;
  }
  return BTreeLevelKSize(root->left, k - 1) + BTreeLevelKSize(root->right, k - 1);
}
//二叉树查找值为x的节点
Tree* BTreeFind(Tree* root,int x)
{
  if (root == NULL)
    return NULL;
  if (root->a == x)
    return root;
  Tree* ret1 = BTreeFind(root->left, x);
  if (ret1)
  {
    return ret1;
  }
  Tree* ret2 = BTreeFind(root->right, x);
  if (ret2)
  {
    return ret2;
  }
}
int main()
{
  Tree* root = CreatTree();
  //前序
  printf("前序:");
  PrevTree(root);
  printf("\n");
  //中序
  printf("中序:");
  HalfTree(root);
  printf("\n");
  //后序
  printf("后序:");
  PostTree(root);
  printf("\n");
  //节点个数
  int count = BTreeSize(root);
  printf("BTreeSize:%d\n", count);
  //叶子节点个数
  printf("BTreeLeafSize:%d\n", BTreeLeafSize(root));
  //树的高度
  printf("BTreeHigh:%d\n", BTreeHigh(root));
  //二叉树第k层节点个数
  printf("BTreeLevelKSize:%d\n", BTreeLevelKSize(root, 3));
  //二叉树查找值为x的节点
  
 
    return 0;
}

运行结果:

总结

总而言之,二叉树其实是对我们运用递归来遍历数据的考察,由于篇幅原因,这里我们只对二叉树的结构进行了大致的讲解,有不理解的地方欢迎与我私信或者在评论区中指出

创作不易,还请各位大佬点个小小的赞!!!

相关文章
|
17天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
59 16
|
17天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
66 8
|
1月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
21 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
1月前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
25 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
|
1月前
|
Java
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
27 1
|
1月前
|
算法 Java C语言
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
24 1
|
1月前
|
存储
【数据结构】二叉树链式结构——感受递归的暴力美学
【数据结构】二叉树链式结构——感受递归的暴力美学
|
1月前
|
存储 算法 调度
数据结构--二叉树的顺序实现(堆实现)
数据结构--二叉树的顺序实现(堆实现)
|
1月前
【高阶数据结构】二叉树进阶探秘:AVL树的平衡机制与实现详解(三)
【高阶数据结构】二叉树进阶探秘:AVL树的平衡机制与实现详解
|
1月前
【高阶数据结构】二叉树进阶探秘:AVL树的平衡机制与实现详解(二)
【高阶数据结构】二叉树进阶探秘:AVL树的平衡机制与实现详解

热门文章

最新文章