优先级队列实现为单一链接,无法更新插入的指针转换

Priority Queue implemented as singly linked failing to update pointer refrence on insert

本文关键字:更新 插入 转换 指针 实现 队列 单一 链接 优先级      更新时间:2023-10-16

编辑的问题:如何将指针参考作为参数的同时插入链接列表中?我更新的代码如下:

注意:我有一个队列的副本,用于将给定节点插入正确的位置,但是我无论如何都没有看到以更新原始队列,因为没有办法链接以前的节点。

解决:工作优先级队列(FIFO) - 需要清洁

#define QUEUE_HEAD_INDICATOR 0.0
namespace
{
    pq* create_node(float priority = 0, const string & text = "")
    {
        pq* q = new pq;
        q->priority = priority;
        q->text = text;
        q->next = nullptr;
        return q;
    }
}
pq* init_priority_queue() {
    return create_node(QUEUE_HEAD_INDICATOR);
}

void insert(pq* &queue, string text, float priority) {
    if (!queue) return;
    pq* prev = queue;
    pq* cursor = queue->next;
    int offset = 0;
    if(prev->priority == 0.0 && prev->text == "") {
        prev->priority = priority;
        prev->text = text;
        return;
    }
    if(!cursor) {
        if(prev->priority > priority) {
            pq* node = create_node(priority, text);
            node->next = prev;
            prev = node;
        } else {
            pq* node = create_node(priority, text);
            prev->next = node;
        }
    } else {
        while(cursor && cursor->priority < priority) {
            prev = cursor;
            cursor = cursor->next;
            offset++;
        }
        pq* node = create_node(priority, text);
        if(offset == 0) {
            if(cursor->priority == (int)node->priority) {
                node->next = prev->next;
                prev->next = node;
                queue = prev;
            } else {
                node->next = prev;
                prev = node;
                queue = prev;
            }
        } else if(!cursor) {
            prev->next = node;
        } else {
            node->next = prev->next;
            prev->next = node;
        }
        return;
    }
}

string remove(pq* &queue) {
    pq* prev = queue;
    pq* cursor = queue->next;
    if(!queue->next) {
        string text = queue->text;
        prev = NULL;
        return text;
    }
    while(cursor->next) {
        prev = cursor;
        cursor = cursor->next;
    }
    prev->next = NULL;
    string text = cursor->text;
    return text;
}

这是结构的样子

struct pq {
    float priority;
    string text;
    pq* next;
};

我需要在此处做一个假设: queue是指向链接列表的头节点的指针的引用。这似乎是一个合理的假设,因为它在if(queue->next == NULL)情况下使用的方式。

以下代码将覆盖指向头节点的指针,然后将每个节点泄漏。

while(queue->next && queue->next->key < priority) {
    queue = queue->next; // bam! previous node leaked back at the caller
}

您可以使用头节点的副本,但是...有更好的方法来处理此操作。

我的建议是不要将指针传递给根节点。将指针传递到指针。通过使头部看起来完全像其他节点并消除大多数代码,可以处理头情况。由于我们总是保留一个指向上一个节点的next的指针,因此我们可以轻松访问新节点的插入点和下一个节点。

您不能用参考来执行此技巧,因为无法重新分配引用。

示例:

#include <string>
#include <iostream>
// my best guess at what pq looks like
struct pq
{
    pq* next;
    std::string text;
    float key;
};
void insert(pq ** queue, // cannot reseat ref, so pointer required
            const std::string &text, // ref eliminates copy.
                                     // const because we don't want to change
            float priority) {
    while((*queue) && // search while more queues
            (*queue)->key < priority) // and priority is low
    {
        queue = &(*queue)->next;
    }
    *queue = new pq{*queue, // if queue is null, end of list, if not inserted in middle
                    text, 
                    priority}; 
}
// Demo
int main()
{
    pq * queue = NULL;
    insert(&queue, "c", 5);
    insert(&queue, "a", 1);
    insert(&queue, "b", 2.5);
    insert(&queue, "e", 10);
    insert(&queue, "d", 7.5);
    // print and clean-up.
    while (queue)
    {
        std::cout << queue->text << std::endl;
        pq * temp = queue; // temp so we don't lose queue
        queue = queue->next;
        delete temp; // release node
    }
}

分配queue = new_node分配了插入函数的参数,而不是链接列表中间的指针(这是上一个元素的next成员变量)。

    pq* qp = new pq;
    insert(qp, "0.1", 0.1f);
    // qp -> 0.1
    insert(qp, "0.3", 0.3f);
    // qp -> 0.1 -> 0.3
    insert(qp, "0.2", 0.2f);
    // qp -> 0.2 -> 0.3
    // qp now points to the 0.2 element, leaving the 0.1 element inaccessible

您的功能也永远不会将第一个元素的优先级与要插入长度> 1的队列的元素的优先级。您的wir循环仅比较要插入的元素的优先级与第一个元素以外的元素的优先级。