堆(Heap)

下标关系
已知双亲(parent)的下标,则:
左孩子(left)下标 = 2 parent + 1;
右孩子(right)下标 = 2
parent + 2;
已知孩子(不区分左右)(child)下标,则:
双亲(parent)下标 = (child - 1) / 2
堆(heap)
定义:

  1. 堆逻辑上是一棵完全二叉树
  2. 堆物理上是保存在数组中
  3. 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆, 或者最大堆
  4. 反之,则是小堆,或 者小根堆,或者最小堆
  5. 堆的基本作用是,快速找集合中的最值。
    向下调整:时间复杂度:O(log(n))
    前提:左右子树必须已经是一个堆,才能调整。
    说明:
  6. array 代表存储堆的数组
  7. size 代表数组中被视为堆数据的个数
  8. index 代表要调整位置的下标
  9. left 代表 index 左孩子下标
  10. right 代表 index 右孩子下标
  11. min 代表 index 的最小值孩子的下标
    过程(以小堆为例):
  12. index 如果已经是叶子结点,则整个调整过程结束
    1. 判断 index 位置有没有孩子
    2. 因为堆是完全二叉树,没有左孩子就一定没有右孩子,所以判断是否有左孩子
    3. 因为堆的存储结构是数组,所以判断是否有左孩子即判断左孩子下标是否越界,即 left >= size 越界
  13. 确定 left 或 right,谁是 index 的最小孩子 min
    1. 如果右孩子不存在,则 min = left
    2. 否则,比较 array[left] 和 array[right] 值得大小,选择小的为 min
  14. 比较 array[index] 的值 和 array[min] 的值,如果 array[index] <= array[min],则满足堆的性质,调整结束
  15. 否则,交换 array[index] 和 array[min] 的值
  16. 然后因为 min 位置的堆的性质可能被破坏,所以把 min 视作 index,向下重复以上过程。
    //向下调整成小堆
    public static void shiftDownSmall(int[]array,int size,int index){
    int left=2*index+1;
    while(left<size){
        int right=left+1;
        int min=left;
        while(right<size){
            if(array[left]>array[right]){
                min=right;
            }
            if(array[index]>array[min]){
                swap(array,index,min);
                index=min;
                left=2*index+1;
            }
            else{
                break;
            }
        }
    }
    }
    public static void swap(int array[],int i,int j){
    int t=array[i];
    arrat[i]=array[j];
    array[j]=t;
    }
    //向下调整成大堆
    public static void shiftDownBig(int[]a,int i,int s){
    while(2*i+1<s) {
      int m=2*i+1;
      if(m+1<s&&a[m+1]>a[m]){
          m++;
      }
      if(a[i]>=a[m]){
          break;
      }
      swap(a,i,m);
      i=m;
      }
    }

向上调整

****//向上调整成小端
//直到index=0,执行循环
//找到index的双亲
//比较index和双亲的值,满足,调整结束,否则交换,然后让i=parent继续
pubic static void shiftUpSmall(int[]array,int size,int index){
    while (index!=0){
        int parent=(index-1)/2;
        if(array[parent]<=array[index]){
           break;
        }
        swap(array,parent,index);
        index=parent;
    }
}
```**

**建堆**

public static void creatHeapBig(int[]array,int size){
for(int i=(s-2)/2;i>=0;i++){
shiftDownBig(a,i,s);
}
}


**优先级队列**
* 出队列:将[0]位置和[size-1]位置交换,然后做一次向下调整。
* 入队列(O(logn)):做向上调整。
* 返回队首元素:即返回[0]下标。

public class MyPriorityQueue {
// 不做扩容考虑
private int[] array;
private int size;

MyPriorityQueue() {
array = new int[16];
size = 0;
}
//入队列
public void offer(int element) {
array[size++] = element;
Heap.shiftUpSmall(array, size - 1);
}
// 出队列O(log(n))
public int poll() {
int element = array[0];
array[0] = array[--size];
Heap.shiftDownSmall(array, 0, size);
return element;
}
//取队首元素
public int peek() {
// 不做错误处理
return array[0];
}


**TopK问题**:在海量数据中找前k大的数据
            找前K个大的,建K个大小的小堆;
            找前k个小的,建K个大小的大堆;
**堆排序**

public static void heapSort(int[] array){
creatHeapBig(array,array.length);
for(int i=0;i<array.length-1;i++){
//无序[0,array.length-i)
//有序[array.length-i,array.length)
swap(array,i:0,j:array.length-i-1-1);
//无序[0,array.length-i-1)
//长度 array.length-i-1
shiftDownBig(array,i:0,s:array.length-i-1);
}
}

原文地址:https://blog.51cto.com/14234314/2440136

时间: 2024-10-28 21:27:04

堆(Heap)的相关文章

JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )

这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解JAVA的底层和运行机制有比较大的帮助.废话不想讲了.入主题:先了解具体的概念:JAVA的JVM的内存可分为3个区:堆(heap).栈(stack)和方法区(method) 堆区:1.存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指令)2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身栈区:1.每个线程包含一个栈区,栈中只保存基础数

.NET中的堆(Heap)和栈(Stack)的本质

计算机的内存可以分为代码块内存,Stack内存和Heap内存.代码块内存是在加载程序时存放程序机器代码的地方. 栈(Stack)一般存放函数内的局部变量. 堆(Heap)一般存放全局变量和类对象实例等. 若只是声明一个对象,则先在栈内存中为其分配地址空间,若再实例化它,则在堆内存中为其分配空间. 1.Stack VS Heap 由于计算机的内存分配过程比较抽象,下面举一个简单的程序片段,来图解和谐步骤对Stack和Heap内存的影响: 下面的StackVsHeap类有一个Person类和Fun1

Java里的堆(heap)栈(stack)和方法区(method)

基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收.局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收. 方法调用时传入的 literal 参数,先在栈空间分配,在方法调用完成后从栈空间分配.

【数据结构】堆heap

本节研究堆heap的相关操作实现: 堆 说明几点 (1)堆分为大根堆和小根堆:大根堆的根为最大值,每一个节点的值都不小于其孩子的值: (2)可以利用大根堆实现升序排序:主要是利用大根堆的头和需要排序的最后一个数字交换的思想: (3)使用大根堆实现最大优先级队列,类似stl中queue的操作,只是对于元素在队列中的元素优先级是不一样的,在最大优先级中,队列头为值最大元素:可利用大根堆来维护一个最大优先级队列:向优先级队列中push元素,类似像堆的末尾添加一个元素,然后使用_makeHeapUp寻找

堆(heap)和栈(stack)几点认识

堆(heap)和栈(stack)主要的区别由以下几点:1.管理方式不同:2.空间大小不同:3.产生碎片不同:4.生长方向不同:5.分配归属不同:6.分配效率不同:7.存取效率不同:管理方式:对于栈来讲,释放是由程序自动管理,无需在程序中手工控制:对于堆来说,释放工作由程序员控制,容易产生memory leak.产生碎片:对于堆来讲,频繁的new/delete,malloc/free势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低.对于栈来讲,则不会存在这个问题,因为栈是先进后出的队

iOS数据存储类型 及 堆(heap)和栈(stack)

iOS数据存储类型 及 堆(heap)和栈(stack) 一般认为在c中分为这几个存储区: 1栈 --  由编译器自动分配释放. 2堆 --  一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收. 3全局区(静态存储区)-- 全局变量和静态变量的存储是放在一块区域 ,程序退出后自动释放 .全局区又分为全局初始化区和全局未初始化区.初始化的全局变量和静态变量存放在全局初始化区,未初始化的全局变量和未初始化的静态变量存放在相邻的另一块区域. 4常量区-- 专门放数字/字符常量的地方, 程

堆heap和栈Stack(百科)

堆heap和栈Stack 在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除.在单片机应用中,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场.要点:堆,队列优先,先进先出(FIFO—first in first out)[1]  .栈,先进后出(FILO—First-In/Last-Out). 目录 1 简介 2 对比分析 ? 堆栈空间分配 ? 堆栈缓存方式 ? 堆栈

(转)堆heap和栈stack

一 英文名称 堆和栈是C/C++编程中经常遇到的两个基本概念.先看一下它们的英文表示: 堆――heap 栈――stack 二 从数据结构和系统两个层次理解 在具体的C/C++编程框架中,这两个概念并不是并行的.深入到汇编级进行研究就会发现,栈是机器系统提供的数据结构,而堆是由C/C++函数库提供的.这两个概念可以从数据结构和系统两个层次去理解: 1.从数据结构层次理解,栈是一种先进后出的线性表,只要符合先进后出的原则的线性表都是栈.至于采用的存储方式(实现方式)是顺序存储(顺序栈)还是链式存储(

编程算法 - 堆(heap) 代码(C)

堆(heap) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 堆(heap)作为二叉树的重要应用, 时间复杂度O(logn), 需要熟练的写出其代码, 基本代码如下, 需要背写. 代码: /* * main.cpp * * Created on: 2014.7.20 * Author: spike */ /*eclipse cdt, gcc 4.8.1*/ #include <stdio.h> class Heap { static const

编程算法 - 篱笆修理(Fence Repair) 堆(heap) 代码(C++)

篱笆修理(Fence Repair) 堆(heap) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目参考: http://blog.csdn.net/caroline_wendy/article/details/37911157 本题比较简单, 直接使用堆(heap)选取两个最小的值, 合并再放入堆, 最后求出和. 比起贪婪算法O(n^2), 时间复杂度O(nlogn). 代码: /* * main.cpp * * Created on: