【数据结构】大根堆和小根堆

简介: 【数据结构】大根堆和小根堆

大根堆实现逻辑

从整棵树的最后一颗子树开始调整,每次都让根节点和左右孩子去比较,如果根节点比左右孩子的最大值要小,那么就将这两个值进行交换,然后此时这颗子树变成了大根堆,再看下一颗树

然后对下一颗树进行相同的处理方法,后面的子树依次交换:


当每棵子树都是大根堆的情况下,那么这棵树也就是大根堆了

每一次交换的步骤为:

  1. 从最后一棵树开始调整
  2. 左右孩子的最大值和根节点进行比较,如果大于根节点,就交换

遇到的主要问题

第一组根节点和左孩子节点的值在哪


  1. 既然调整要从最后一棵子树的根节点开始,那如何确定最后一棵子树的根节点在哪?
  • 把最后一棵子树的根节点记作 p(parent),左节点的值记作 c(child)
  • 由于堆是由数组实现的,我们最初在创建堆的时候,每一个值都有一个下标,并且是按照层序排序的方式进行完全二叉树的构建,所以原数组的最后一个元素,也就是下标为数组长度-1 (len - 1) 的元素就是最后一个叶子节点,既然知道了最后一棵子树根节点的左孩子节点,那么就可以推出根节点的位置了,p 的下标为:(len-1-1)/2

后续根节点和左孩子节点的值如何确定

  1. 最后一棵子树的根节点和孩子找到了,并且交换完成了,那怎么确定下一棵子树中要交换的一组根节点和左孩子节点的值呢?
  • 之后的根节点 p 只需要在每一交换完成之后进行 p-- 的操作就可以定位到下一棵需要交换的子树的根节点位置了,最后一个 p 的下标为 0
  • 而孩子节点 c 则需要通过根节点的位置进行推导,c 的下标为:2*p+1

右孩子值更大怎么办

  1. 把左孩子节点记作 c(child),每次都是 c(child) 与根节点 p(parent) 进行交换,那要是右孩子节点比左孩子节点要大呢?

因为我们每次都是对左右孩子的最大值与根节点进行交换,所以我们要时刻保证 c(child) 代表的是左右孩子中更大的那个。

由于 c(child) 最先是指向左孩子的,

  1. 若左孩子节点 > 右孩子节点,继续进行交换
  2. 若左孩子节点 < 右孩子结点,则 child++,让 child 代表右孩子

这一切都是发生在每一次准备进行交换的前一刻,为将要交换的 childparent 提供准确的数据


什么时候一轮交换结束

  1. 在每一次进行交换操作的时候,什么时候代表交换结束呢?


如何进行交换操作

  1. 需要交换的元素知道了,交换开始的条件知道了,交换的结束条件也知道了,那该如何进行交换操作呢?

此时我们创建一个 swap(int i, int j) 交换方法:

  1. 创建一个 tmp 整型变量,用来存放 elem[i] 的值
  2. 再将 elem[i] 的值赋给 elem[i]
  3. 最后将 tmp 中存放的 elem[i] 的值赋给 elem[j]

大根堆完整代码

public void creatHeap(){  
    for (int parent = (usedSize-1-1)/2; parent >= 0 ; parent--) {  
        shiftDown2(parent,usedSize);  
    }
}  
  
public void swap(int i, int j) {  
    int tmp = elem[i];  
    elem[i] = elem[j];  
    elem[j] = tmp;  
}  
  
  
public void shiftDown(int parent, int end) {  
    //parent的值是作为参数传进来的,我们需要用parent的下标算出child的下标  
    int child = parent*2+1;  
    
    //每一轮交换进行的条件  
    while(child < end){  
        //右节点比左节点大的时候,但前提是右节点必须存在  
        if(child+1 < end && elem[child+1] > elem[child]){  
            child++;  
        }        
      //调整过后,child代表的就永远都是更大的子节点  
        
        //当子节点比根节点大时,进行交换  
        if(elem[child] > elem[parent]){  
            swap(parent,child);  
            parent = child;  
            child = 2*parent+1;  
        }else {  
            //若子节点小于根节点,则跳出循环  
            break;  
        }    
    }
}

观察调试结果,可发现已变成大根堆

小根堆的实现

小根堆的实现只需要在大根堆实现的基础上将

  1. child 的指向改为指向更小的那个节点:
    if (child + 1 < end && elem[child + 1] < elem[child]) {child++;}
  2. parentchild 交换的条件改为 if (elem[child] < elem[parent])

小根堆的代码与大根堆相似度高达 99%,只需要将 shiftDown 方法中的第 7 和 13 行进行微微调整即可

public void shiftDown2(int parent, int end) {  
    //parent的值是作为参数传进来的,我们需要用parent的下标算出child的下标  
    int child = parent * 2 + 1;  
    //一轮交换进行的条件  
    while (child < end) {  
        //右节点比左节点大的时候,但前提是右节点必须存在  
        if (child + 1 < end && elem[child + 1] < elem[child]) {  
            child++;  
        }        
        //调整过后,child代表的就永远都是更小的子节点  
        
        //当子节点比根节点小时,进行交换  
        if (elem[child] < elem[parent]) {  
            swap(parent, child);  
            parent = child;  
            child = 2 * parent + 1;  
        } else {  
            //若子节点大于根节点,则跳出循环  
            break;  
        }   
    }
}

观察调试结果,可发现已变成小根堆


相关文章
|
2月前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
53 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
2月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
133 16
|
3月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
147 1
|
4月前
|
存储 Java
【数据结构】优先级队列(堆)从实现到应用详解
本文介绍了优先级队列的概念及其底层数据结构——堆。优先级队列根据元素的优先级而非插入顺序进行出队操作。JDK1.8中的`PriorityQueue`使用堆实现,堆分为大根堆和小根堆。大根堆中每个节点的值都不小于其子节点的值,小根堆则相反。文章详细讲解了如何通过数组模拟实现堆,并提供了创建、插入、删除以及获取堆顶元素的具体步骤。此外,还介绍了堆排序及解决Top K问题的应用,并展示了Java中`PriorityQueue`的基本用法和注意事项。
77 5
【数据结构】优先级队列(堆)从实现到应用详解
|
3月前
|
存储 算法 调度
数据结构--二叉树的顺序实现(堆实现)
数据结构--二叉树的顺序实现(堆实现)
|
3月前
|
存储 算法 分布式数据库
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
|
3月前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
3月前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
48 0
|
3月前
|
存储 算法
【数据结构】二叉树——顺序结构——堆及其实现
【数据结构】二叉树——顺序结构——堆及其实现
|
3月前
|
存储 算法 搜索推荐
数据结构--堆的深度解析
数据结构--堆的深度解析

热门文章

最新文章