由于您可以通过顺序迭代数组来有效地构建堆:
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)来有效地构建堆?
答案 0 :(得分:0)
堆的值存储在可读写索引数组中。例如,bubble_up
需要能够以非顺序的顺序读取和写入值。有关堆如何进行非顺序访问的更具体示例,请参阅Muhammad Ahmad的答案。
因此,无法在链表(或双向链表)中存储和维护堆的值,因为它仅支持顺序访问。 (更具体地说:链接列表中的非顺序访问是可能的,但它通常太慢。因此,构建和使用基于链表的堆将太慢。)
可以将链表转换为堆,方法是从空堆开始,遍历链表,然后将链表中的每个元素插入堆中。最后会有两个值的副本:一个在链表中,一个在堆中。然后可以删除链接列表。在迭代过程中也可以删除每个值。
无法将链接列表转换为堆(不复制值或不会太慢),因为堆需要非顺序访问,链接列表只能有效地提供顺序访问。
答案 1 :(得分:0)
我想,这会回答你的问题。
删除和插入堆中通常需要将节点的数据与其父节点或其子节点(左侧或右侧或两者)进行比较。
它是包含最大堆数据的数组的简单示例。 (请参阅索引0被忽略或未使用,根元素存储在索引1,它的子节点存储在索引2处,右子节点存储在索引3处,依此类推。)
使用这种实现的好处是,对于索引为i
的节点,我们始终可以在索引i / 2
获取它的父节点,它的左边是子节点索引2 * i
和2 * i + 1
如果需要将节点与其父母或孩子进行比较,我们可以轻松地立即获取其父母或孩子的索引。并直接访问所需的节点(因为它是一个数组)。
但是在链表的情况下,你不能直接访问它的父或子,这个链表并不是实现堆的快捷方式。