为什么有效的堆构造需要随机访问?

时间:2016-08-22 12:28:22

标签: c data-structures

由于您可以通过顺序迭代数组来有效地构建堆:

make_heap(priority_queue *q, item_type s[], int n)
{
    int i; /* counter */

    priority_q_init(q);
    for (i=0; i<n; i++)
        priority_q_insert(q, s[i]);
}

priority_q实现的一部分(如果有帮助):

priority_q_insert(priority_queue *q, item_type x)
{
    if (q->n >= PQ_SIZE)
        printf("warning...overflow");
    else {
        q->n = (q->n) + 1;
        q->q[ q->n ] = x;
        bubble_up(q, q->);
    }
}

为什么不能通过顺序迭代链表(which it appears you can do)来有效地构建堆?

2 个答案:

答案 0 :(得分:0)

堆的值存储在可读写索引数组中。例如,bubble_up需要能够以非顺序的顺序读取和写入值。有关堆如何进行非顺序访问的更具体示例,请参阅Muhammad Ahmad的答案。

因此,无法在链表(或双向链表)中存储和维护堆的值,因为它仅支持顺序访问。 (更具体地说:链接列表中的非顺序访问是可能的,但它通常太慢。因此,构建和使用基于链表的堆将太慢。)

可以将链表转换为堆,方法是从空堆开始,遍历链表,然后将链表中的每个元素插入堆中。最后会有两个值的副本:一个在链表中,一个在堆中。然后可以删除链接列表。在迭代过程中也可以删除每个值。

无法将链接列表转换为堆(不复制值或不会太慢),因为堆需要非顺序访问,链接列表只能有效地提供顺序访问。

答案 1 :(得分:0)

我想,这会回答你的问题。

删除和插入堆中通常需要将节点的数据与其父节点或其子节点(左侧或右侧或两者)进行比较。

enter image description here

它是包含最大堆数据的数组的简单示例。 (请参阅索引0被忽略或未使用,根元素存储在索引1,它的子节点存储在索引2处,右子节点存储在索引3处,依此类推。)

使用这种实现的好处是,对于索引为i的节点,我们始终可以在索引i / 2获取它的父节点,它的左边是子节点索引2 * i2 * i + 1

的右孩

如果需要将节点与其父母或孩子进行比较,我们可以轻松地立即获取其父母或孩子的索引。并直接访问所需的节点(因为它是一个数组)。

但是在链表的情况下,你不能直接访问它的父或子,这个链表并不是实现堆的快捷方式。