堆相关问题

讲堆不得不提的就是优先队列。

什么是优先队列?

普通队列:先进先出,后进后出

优先队列:出队顺序和入队顺序无关;和优先级相关

如何实现优先队列?

由上图可知,用堆来实现优先队列是一个理想的方法。

这里采用二叉堆(最大堆)的定义:

  1.   所有节点的值都不大于其父节点的值
  2.   二叉堆是一个完全二叉树
采用数组来存储二叉堆

由二叉堆的定义可以得出结论:对一颗完全二叉树按层序遍历编号,根节点的编号为1, 假设父节点的编号为 i , 则任何子节点的编号满足:

  • left child = i * 2
  • right child = i * 2 + 1

用C++语言一步一步实现最大堆

初始化:

#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;

//MaxHeap implements
template <typename Item>
class MaxHeap{

private:
    Item* data;
    int count;//堆的大小
    int capacity;
public:
    MaxHeap(int capacity) {
        data = new Item[capacity + 1];
        count = 0;
        this->capacity = capacity;
    }

    ~MaxHeap() {
        //释放内存空间
        delete [] data;
    }

    //return the size of maxheap
    int size() {
        return count;
    }

    int isEmpty() {
        return count == 0;
    }
    void print() {
        for(int i = 0; i <= this->count; i++) {
            cout << data[i] << "  ";
        }
        cout << endl;
    }
};
int main() {
    MaxHeap<int> maxheap = MaxHeap<int>(100);
    cout << maxheap.size() << endl;
    srand(time(NULL));
    return 0;
}
插入一个值:

首先将插入值放在数组的最后面,然后将值与父节点比较,如果父节点的值比插入值大,则当前位置就是合适位置;如果父节点的值比插入值小,则当前位置不合适,将当前值与父节点值交换,然后再向上比较。直到父节点的值比插入值大或者已到根节点。

void shiftUp(int k) {
    while(k > 1 && data[k/2] < data[k]) {
        swap(data[k / 2], data[k]);
        k /= 2;
    }
}
//插入一个值
void insert(Item item) {
    assert(count + 1 <= capacity );
    data[count + 1] = item;
    count++;
    shiftUp(count);
}
推出一个值:

    在最大堆中推出一个值,即最大值,也就是二叉树的根节点。

    可以先将数组中的最后一个元素赋值给第一个元素,由于我们堆有一个对的大小属性维护,不用删除最后一个元素的值。

    然后由根节点一次向下比较左右两个字节点的大小,如果左字节点小于右字节点,那么将右子节点与父节点交换,否则与左字节点交换。

void shiftDown(int k) {

    while( 2 * k <= count) {

        int j = 2 * k;//在次轮循环中,data[k]和data[j]交换位置
        if( j + 1 <= count && data[j + 1] > data[j])
            j++;

        if(data[k] >= data[j])
            break;
        swap(data[j], data[k]);
        k = j;
    }
}
Item extractMax() {
    assert(count > 0);
    Item ret = data[1];
    swap(data[1], data[count]);
    count--;
    shiftDown(1);
    return ret;
}
索引堆

当我们要建立堆的数据结构过于复杂时,交换元素困难,我们可以考虑使用索引堆,即采用一个indexes数组存储二叉最大堆的索引值,data数组存储值,每次只交换索引,而不交换值。这里给出一种实现方式。

template <typename Item>
class IndexMaxHeap{

private:
    int *indexes;
    Item* data;
    int count;//堆的大小
    int capacity;
    void shiftUp(int k) {
        while(k > 1 && data[indexes[k/2]] < data[indexes[k]]) {
            swap(indexes[k / 2], indexes[k]);
            k /= 2;
        }
    }

    void shiftDown(int k) {

        while( 2 * k <= count) {

            int j = 2 * k;//在次轮循环中,data[k]和data[j]交换位置
            if( j + 1 <= count && data[indexes[j + 1]] > data[indexes[j]])
                j++;

            if(data[indexes[k]] >= data[indexes[j]])
                break;
            swap(indexes[j], indexes[k]);
            k = j;
        }
    }

public:
    IndexMaxHeap(int capacity) {
        data = new Item[capacity + 1];
        indexes = new int[capacity + 1];
        count = 0;
        this->capacity = capacity;
    }

    ~IndexMaxHeap() {
        //释放内存空间
        delete [] data;
        delete [] indexes;
    }

    //return the size of maxheap
    int size() {
        return count;
    }

    int isEmpty() {
        return count == 0;
    }

    //插入一个值
    //用户以为i通常以为是从0开始索引的
    void insert(int i, Item item) {
        assert(count + 1 <= capacity );
        assert(i + 1 >= 1 && i + 1 <= capacity);
        i++;
        data[i] = item;
        indexes[count + 1] = i;
        count++;
        shiftUp(count);
    }

    void print() {
        for(int i = 0; i <= this->count; i++) {
            cout << data[i] << "  ";
        }
        cout << endl;
    }

    //返回最大的元素
    Item extractMax() {

        assert(count > 0);

        Item ret = data[indexes[1]];
        swap(indexes[1], indexes[count]);
        count--;
        shiftDown(1);
        return ret;
    }

    //返回最大元素的索引
    int extractMaxIndex() {

        assert(count > 0);

        int ret = indexes[1] - 1;
        swap(indexes[1], indexes[count]);
        count--;
        shiftDown(1);
        return ret;
    }

    //由索引来取值
    Item getItem(int i) {
        return data[i + 1];
    }

    void change(int i, Item newItem) {

        i++;
        data[i] = newItem;
        // 找到indexes[j] = i, j表示data[i]在堆中的位置
        //时间复杂度 n + logn, 即O(n)
        for(int j = 0; j <= count; j++)
            if(indexes[j] == i) {
                data[i] = newItem;
                shiftDown(j);
                shiftUp(j);
            }
    }
};






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Java中,指的是运行时数据区中的一块内存区域,它主要用于存储动态创建的对象。Java是由垃圾收集器负责管理的,在Java程序运行时,当没有任何引用指向一个对象时,垃圾收集器会自动将其清除掉,释放内存空间。 Java中的采用的是动态存储分配方式,可以根据需要动态地分配和释放内存空间。在Java中,使用new关键字创建一个对象时,会在中分配一块内存空间,并返回一个引用指向该对象。当对象不再被引用时,垃圾收集器会清除该对象,并释放它占用的内存空间。 Java的特点包括: 1. 中存储的对象大小不需要在编译时确定,可以在运行时动态分配和释放内存空间。 2. 中存储的对象可以共享,多个对象可以引用同一个对象实例。 3. 中的对象由垃圾收集器自动管理,程序员不需要手动释放内存。 4. 中的对象分配速度较慢,因为需要动态分配内存空间。 5. 中的对象访问速度较慢,因为需要通过引用来访问对象。 总之,Java中的是动态分配内存的重要存储区域,用于存储动态创建的对象。程序员不需要手动管理中的对象,垃圾收集器会自动清除不再被引用的对象,并释放占用的内存空间。 ### 回答2: Java中的是一种动态内存分配的区域,用于存储对象。是Java虚拟机管理的,可以动态地分配和释放内存空间。 在Java中,当我们创建一个对象时,对象的实例数据和成员变量都存储在中。的大小是可调整的,可以根据需要动态地调整。 是通过垃圾回收来自动管理内存的。当对象不再被引用时,垃圾回收器会自动回收该对象所占用的内存空间,释放资源。因此,我们可以放心地创建和销毁对象,而不需要手动释放内存。 中的内存分配是一种动态的过程,分配的顺序不是连续的。当我们创建一个对象时,Java虚拟机会在中寻找可以容纳该对象的空间。如果找到合适的内存块,就分配给对象,否则会进行垃圾回收或者触发的扩容。 由于的动态分配和垃圾回收机制,Java程序可以更加灵活地管理内存,避免了内存溢出和内存泄露的问题。同时,也提供了对象的共享和共享数据的支持,使得Java程序的编码更加方便和高效。 总之,Java中的是一种动态内存分配的区域,用于存储对象。它通过垃圾回收来自动管理内存,支持动态调整内存大小。的使用让Java程序的内存管理更加方便、高效和安全。 ### 回答3: Java是一种面向对象的编程语言,而是Java中用于存储动态分配的对象的一种内存区域。 在Java中,使用new关键字创建的对象实例都会被存储在中。是一种共享的内存区域,用于存储所有的对象实例。与之相对的是栈,栈用于存放方法调用和局部变量等数据。 的大小在Java程序运行时是可调的,默认情况下,的初始大小为操作系统的物理内存的1/64,并且可以通过配置参数进行调整。 Java的垃圾收集机制也与紧密相关。Java使用自动垃圾收集器(Garbage Collector)来回收不再使用的对象,从而释放中的内存空间。当一个对象不再被引用时,垃圾收集器会将其标记为可回收的对象,然后在适当的时机将这些对象进行清理和回收。 还可以分为几个不同的区域,包括新生代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation)。新生代用于存放新创建的对象,老年代用于存放长时间存活的对象,而持久代则用于存放Java类的元数据等。 在编写Java程序时,需要注意的使用,避免创建过多的对象和内存泄漏等问题。合理地管理内存的使用,可以提高程序的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值