二叉树的实现(上)

简介: 二叉树的实现

> 作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等

> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:掌握二叉树,掌握二叉树的顺序存储和链式存储。

> 毒鸡汤:要想青春不留遗憾,小伙必须敢想敢干。

> 望小伙伴们点赞👍收藏✨加关注哟💕💕

🌟前言

       谈起二叉树,就不得不谈起树,此时坐在小板凳上的小伙伴们,纷纷举手说,这个我懂。开心的不得了,博主表示你们认知的树,小盆友都懂,😅😅。我们谈的是数据结构的树。


     

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

就像右图,A点就头,其它就像根,长的真丑,😉😉,当然啦,直接给个树给你,都不知道有啥用,咱就介绍一下数据结构中的树相关知识,话不多说。

主体  

🌙树概念及结构

🌝树的相关概念

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6

叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点

非终端节点或分支节点:度不为0的节点; 如上图:DEFG...等节点为分支节点

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:AB的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:BA的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:BC是兄弟节点

树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6

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

树的高度或深度:树中节点的最大层次; 如上图:树的高度为4

堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:HI互为兄弟节点

节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙

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

🌝树的代码实现

      这里的代码可不是就把树就写完了,别想太多😳😳。实现一个简单的树节点,这个实现起来不难,不是本课堂的重点。

//定义数据类型
typedef int HPDataType;
//二叉树堆的实现
typedef struct Heap
{
  //下一个节点
  HPDataType* a;
  //元素个数
  int size;
  //初始化个数
  int capacity;
}HP;

🌙二叉树(重点 )

       看到上面的树,想必大家耳熟能详,有一部分小伙伴学习这个知识点,头都是大的,最讨厌里面的递归,直接把人干蒙了。不过有本宝宝在,不怕不怕😎

🌝二叉树概念及结构

从上图可以看出:

💦1. 二叉树不存在 度大于2结点

💦2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

💤特殊的二叉树

满二叉树:

满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为  K  ,且结点总数是  2^k-1 ,则它就是满二叉树。


完全二叉树:

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

💤二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.

2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .

3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 n0= n1+1

4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2

为底,n+1为对数)

5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:

       💦1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点

       💦2. 若2^i+1左孩子序号:2^i+1,2i+1>=n否则无左孩子

       💦3. 若2^i+2右孩子序号:2^i+2,2i+2>=n否则无右孩子

🌝二叉树的顺序存储结构

      普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

因此这里有关于二叉树的堆的存储,我们来看看堆的存储方式如何实现。

💫主体

咱们从三个方面实现二叉树的堆,动态管理,建小大堆,对元素进行操作。


在程序中为了实现二叉树的堆,需要创建头文件Heap.h ,创建源文件Heap.c,主函数Test.c

🌠动态管理
💤初始化动态二叉树的堆

1.首先我们在Heap.h定义动态的二叉树的堆,省得我们再调用(堆),这里和链表是一样哒。

//定义数据类型
typedef int HPDataType;
//二叉树堆的实现
typedef struct Heap
{
  //下一个节点
  HPDataType* a;
  //元素个数
  int size;
  //初始化个数
  int capacity;
}HP;

2.对堆进行初始化。

//初始化
void HeapInit(HP* php) 
{
  //断言
  assert(php);
  //初始化
  php->a = NULL;
  php->size = 0;
  php->capacity = 0;
}

3.建立二叉树。

//建立二叉树
void HeapInitArray(HP* php, int* a, int n)
{
  //断言
  assert(php);
  assert(a);
  //开辟空间
  php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
  //判断
  if (php->a == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  //赋值
  php->size = n;
  php->capacity = n;
  //把a的元素拷贝的开辟的二叉树中
  memcpy(php->a, a, sizeof(HPDataType) * n);
  // 建堆
  for (int i = 1; i < n; i++)
  {
    //向上调整建小堆 实现取出最小的元素(后面会实现)
    AdjustUp(php->a, i);
  }
}
💤释放堆内存
//销毁
void HeapDestroy(HP* php)
{
  //断言
  assert(php);
  //释放内存
  free(php->a);
  php->a = NULL;
  php->size = php->capacity = 0;
}
🌠建大小堆
💤实现向上调整建小堆
//实现向上调整建小堆
void AdjustUp(HPDataType* a, int child)
{
  //父亲和孩子的关系
  int parent = (child - 1) / 2;
  while (child > 0)
  {
    //实现向上调整元素
    if (a[child] < a[parent])
    {
      Swap(&a[child], &a[parent]);
      child = parent;
      parent = (parent - 1) / 2;
    }
    else
    {
      break;
    }
  }
}
💤实现向下调整建大堆
//实现向下调整建大堆
void AdjustDown(HPDataType* a, int n, int parent)
{
  //孩子和父亲的关系 
  int child = parent * 2 + 1;
  while (child < n)
  {
    //找出小的那个孩子
    if (child + 1 < n && a[child + 1] < a[child])
    {
      ++child;
    }
    //实现向下调整元素
    if (a[child] < a[parent])
    {
      Swap(&a[child], &a[parent]);
      // 继续往下调整
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
}
🌠元素操作
💤打印元素
//打印元素
void HeapPrint(HP* php)
{
  //断言
  assert(php);
  for (size_t i = 0; i < php->size; i++)
  {
    printf("%d ", php->a[i]);
  }
  printf("\n");
}
💤添加元素
//添加元素
void HeapPush(HP* php, HPDataType x)
{
  //断言
  assert(php);
  //扩容(这里实现元素一个添加在堆中)
  //(需要主函数整个循环)
  if (php->size == php->capacity)
  {
    //实现扩容
    int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
    //开辟空间
    HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
    //判断
    if (tmp == NULL)
    {
      perror("realloc fail");
      exit(-1);
    }
    php->a = tmp;
    php->capacity = newCapacity;
  }
  php->a[php->size] = x;
  php->size++;
  //添加元素后实现向上调整 建成小堆
  AdjustUp(php->a, php->size - 1);
}
💤删除元素
//删除元素(这里可以实现排序 (从小到大) )
void HeapPop(HP* php)
{
  //断言
  assert(php);
  assert(php->size > 0);
  //第一个元素和最后一个元素交换
  Swap(&php->a[0], &php->a[php->size - 1]);
  --php->size;
  //向下调整后 就可以剥离出最后一个元素实现排序(小到大)
  AdjustDown(php->a, php->size, 0);
}
💤返回第一个元素
//返回第一个元素
HPDataType HeapTop(HP* php)
{
  //断言
  assert(php);
  assert(php->size > 0);
  //返回第一个元素
  return php->a[0];
}
💤判断不能没有元素
//判断不能没有元素
bool HeapEmpty(HP* php)
{
  //断言
  assert(php);
  //
  return php->size == 0;
}


二叉树的实现(下):https://developer.aliyun.com/article/1389398


目录
相关文章
|
9月前
|
C语言
【二叉树】的实现
【二叉树】的实现
23 0
|
2月前
|
存储
二叉树详解
二叉树详解
28 2
|
11月前
二叉树的讲解
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点. 2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 2^h-1. 3. 对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为02 ,则有n0 =n2 +1 4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2为底,n+1为对数) 5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
二叉树的讲解
|
2月前
|
算法 网络协议 NoSQL
认识二叉树(详细介绍)
认识二叉树(详细介绍)
|
11月前
|
存储
|
11月前
|
存储
【二叉树】(一)
【二叉树】(一)
36 0
|
11月前
|
Java
简单介绍二叉树
简单介绍二叉树
|
12月前
|
存储 机器学习/深度学习 算法
二叉树(详解)中
二叉树(详解)
54 0
|
存储 Java 知识图谱
浅谈二叉树
浅谈二叉树
141 0
浅谈二叉树
#### [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/)
#### [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/)