【完全二叉树魔法:顺序结构实现堆的奇象】(中)

简介: 【完全二叉树魔法:顺序结构实现堆的奇象】

【完全二叉树魔法:顺序结构实现堆的奇象】(上):https://developer.aliyun.com/article/1424931


4.堆的调整算法


4.1堆向下调整算法


现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

//向下调整
void AdjustDown(HPDataType* a, int n, int parent)
{
  int child = parent * 2 + 1;
  //parent到叶子结点就结束
  while (child < n)
  {
    //可能不存在右孩子
    if (child + 1 < n && a[child] > a[child + 1])
    {
      child++;
    }
    if (a[child] < a[parent])
    {
      Swap(&a[child], &a[parent]);
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
}


4.2堆向上调整算法


       现在我们给出一个数组,前n-1个数已经是堆了,现在再添加一个数要让其满足堆的性质。我们通过从最后一个叶子结点向上调整算法可以把它调整成一个小堆。向上调整算法有一个前提:前面的数据必须是一个堆,才能调整。

//向上调整
void AdjustUp(int* a, int child)
{
  int parent = (child - 1) / 2;
  while (child > 0)
  {
    if (a[child] < a[parent])
    {
      Swap(&a[child], &a[parent]);
      child = parent;
      parent = (child - 1) / 2;
    }
    else
    {
      break;
    }
  }
}


5.堆的创建


方法一:向上调整插入的思想


       下面我们给出一个数组,利用上面push函数的思路,将数组a中的元素依次插入向上调整,把第一个数当成堆,满足堆向上调整的前提,可以调整成堆。

int a[] = {1,5,3,2,8};

//建堆
//向上调整:前提是前面的数据是堆
// 思路:第一个数据当作堆,后面数据依次插入,向上调整
//时间复杂度O(N*logN)
for (int i = 1; i < n; i++)
{
  AdjustUp(a, i);
}

所以这里我们就可以给堆结合实现一个创建堆的接口:使用向上调整的思路。

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 = php->capacity = n;
  memcpy(php->a, a, sizeof(HPDataType) * n);
  for (int i = 0; i < n; i++)
  {
    AdjustUp(php->a, i);
  }
}

   因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):


因此:建堆的时间复杂度为O(N*logN)。


方法二:倒数第一个非叶子结点向下调整的思想


   下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。如果根节点左右子树是堆,我们可以直接向下调整即可,但是此时根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树与其叶子结点开始向下调整,调整完直接下标减一就是倒数的第二个非叶子节点,一直调整到根节点的树,就可以调整成堆。

int a[] = {1,5,3,8,7,6}; 
//倒数第一个非叶子结点:(最后一个叶子结点-1)/2 

//建堆
//向下调整建堆
//找到倒数第一个非叶子结点
//时间复杂度O(N)
for (int i = (n - 1 - 1)/2; i >= 0; i--)
{
  AdjustDown(a, n, i);
}


【完全二叉树魔法:顺序结构实现堆的奇象】(下):https://developer.aliyun.com/article/1424935

相关文章
|
前端开发 JavaScript Java
JAVAEE框架技术之4springMVC入门
JAVAEE框架技术之4springMVC入门
181 0
JAVAEE框架技术之4springMVC入门
|
C# 数据库
用C#连接到数据库实现学生学籍管理系统(二)
用C#连接到数据库实现学生学籍管理系统
|
JavaScript
html+css+js实现文本编辑器
html+css+js实现文本编辑器
164 0
|
存储 前端开发
A-B罗克韦尔 1771-A4B 通用I/O机箱 16槽机箱
Allen-Bradley 1771-A4B 是一款16槽通用I/O机箱,适用于1771 PLC系列。设计用于面板安装,它提供24 A最大背板电流,重量为7.3千克。机箱工作温度范围为32-140°F (0-60°C),支持5-95%非冷凝湿度。1771-A4B有16个插槽,尺寸为12.4 x 24 x 7.6英寸,配备5V 8A直流背板。这款机箱兼容1771系列的小型、灵活、性价比高的I/O模块,支持热插拔和故障诊断指示灯。推荐相关产品包括模块接口板、扩展器和控制器模块等。
|
Web App开发 机器学习/深度学习 安全
2022年来点不一样的体验,玩一玩云桌面吧!
最近阿里云推出云桌面体验活动,有幸被邀请参加。 作为一个开发者,和代入一个企业管理者的角度,分享一下云应用的使用。 整个过程非常顺畅,加上个人技巧,特此分享一下感受。
814 0
2022年来点不一样的体验,玩一玩云桌面吧!
|
SQL 运维 关系型数据库
分布式关系型数据库服务DRDS——DRDS 主要解决的问题和DRDS的主要功能
分布式关系型数据库服务DRDS——DRDS 主要解决的问题和DRDS的主要功能,
869 0
分布式关系型数据库服务DRDS——DRDS 主要解决的问题和DRDS的主要功能
|
小程序 测试技术
【技巧】软件测试的面试这些技巧记得不要错过了
拥有一个心仪的offer,是每个软件测试工程师们都梦寐以求的事情,那如何才能通过最后的面试一关,拿到offer呢? 俗话说,知己知彼百战不殆,作为测试员,在面试前对面试官可能提出的问题进行总结和准备,是帮助我们取得好成绩的最佳方式,所以,这些有关软件测试的面试技巧记得不要错过了!
265 0
阿里数据中心数字孪生可视化
IDC 数字孪生产品的系统性解决方案。
阿里数据中心数字孪生可视化
|
存储 Java 编译器
【C++初阶:类和对象(下篇)】初始化列表 | static成员 | 友元 下
【C++初阶:类和对象(下篇)】初始化列表 | static成员 | 友元
181 0
【C++初阶:类和对象(下篇)】初始化列表 | static成员 | 友元 下
|
Java Python
Python基础之:Python中的模块
Python基础之:Python中的模块