为什么我的基本优先级队列排序算法会导致 seg 错误

Why is my basic PriorityQueue sorting algorithm causing a seg fault?

本文关键字:seg 错误 算法 我的 基本优先级 队列 排序 为什么      更新时间:2023-10-16

我已经在这个链表优先级队列上工作了四五个小时,在我的一生中,我找不到这个 seg 错误的根源。这让我发疯了。

我知道问题的根源在于我的 swapUp() 函数(根据它们的优先级交换两个节点的位置),因为该列表在调用之前运行良好。seg 错误实际上不是由 swapUp() 引起的,而是由 peekAt() 引起的,它返回节点中位置 n 处的元素。但是除非首先调用 swapUp(),否则不会发生错误,所以这就是问题所在(我认为)。

析构函数中还存在一个 seg 错误,我相信这可能在 swapUp() 中具有相同的根本原因。

我已经一遍

又一遍地检查代码,并且整晚都在调试它,但我无法弄清楚到底出了什么问题。我真的非常感谢这方面的帮助。

优先级队列:

#ifndef JMF_PriorityQueue
#define JMF_PriorityQueue
#include <iostream>
#include <string>
template <typename T>
class PriorityQueue{
    public:
        struct Node{
            T data;
            int priority;
            Node * next;
            Node * prev;
        };
    PriorityQueue();
    PriorityQueue & operator=(const PriorityQueue &rhs);
    bool isEmpty();         //Returns true if queue is empty
    int getLength();        //Returns length of queue
    void enqueue(T data, int p);    //Enqueues data T with priority p
    void enqueue(T data);           //Enqueues data T with priority 1
    T dequeue();                    //Dequeues and returns data at head of queue
    void clearQueue();              //Empties queue
    T peek();                       //Returns data at head of queue without dequeing it
    T peekAt(int n);                //Returns data element n without dequeuing it
    int getPriority(int n);         //Returns priority of item at position n
    void display();                 //Prints list of data elements to screen
    void revDisplay();
    void swapUp(Node * target);     //Swaps target node with it's neighbor next in line
    bool contains(T data);          //Returns true if data exists as an element anywhere on the queue
    ~PriorityQueue();
    private:
        int size;
        Node * head, *tail;
};
template <typename T>
PriorityQueue<T>::PriorityQueue(){
    size = 0;
    head = 0;
    tail = 0;
}
template <typename T>
PriorityQueue<T> & PriorityQueue<T>::operator=(const PriorityQueue &rhs){
    clearQueue();
    for(int n = 0; n < rhs.size(); n++)
        enqueue(rhs.peekAt(n));
    return *this;
}
template <typename T>
int PriorityQueue<T>::getLength(){
    return size;
}
template <typename T>
bool PriorityQueue<T>::isEmpty(){
    return(!size);
}
template <typename T>
void PriorityQueue<T>::enqueue(T data){
    enqueue(data, 1);
}
template <typename T>
void PriorityQueue<T>::enqueue(T data, int p){
    Node * newNode = new Node();
    newNode -> data = data;
    newNode -> priority = p;
    if(isEmpty()){
        head = newNode;
        tail = newNode;
    } else {
        newNode -> next = tail;
        tail -> prev = newNode;
        tail = newNode;

        //WHEN THIS WHILE LOOP IS COMMENTED OUT (IE NO SORTING), NO SEG FAULT ISSUES
        while(newNode != head && newNode->priority < newNode->next->priority)
            swapUp(newNode);
        std::cout << "n";
    }
    tail->prev = 0;
    head->next = 0;
    size++;
}
template <typename T>
T PriorityQueue<T>::dequeue(){
    if(isEmpty()){
        std::cout << "nnWARNING: Trying to dequeue empty queuenn";
        throw 3;
    } else {
        Node * frontNode = head;
        T result = frontNode -> data;
        if(size == 1){
            head = 0;
            tail = 0;
        } else {
            head = frontNode -> prev;
            head -> next = 0;
        }
        delete frontNode;
        size--;
        return result;
    }
}
template <typename T>
void PriorityQueue<T>::clearQueue(){
    while(!isEmpty())
        dequeue();
}
template <typename T>
T PriorityQueue<T>::peek(){
    return peekAt(0);
}
template <typename T>
T PriorityQueue<T>::peekAt(int n){
    T result;
    Node * thisNode;
    if(isEmpty()){
        std::cout << "nnWARNING: Trying to peek empty queuenn";
        throw 3;
    } else if( n < 0 || n > size){
        std::cout << "nnWARNING: Trying to peek queue at non-existent index " << n << "nn";
        throw 3;
    } else {
        thisNode = head;
        if(thisNode->prev == 0)
        for(int k = 0; k < n; k++)
            thisNode = thisNode -> prev;
        result = thisNode -> data;              //Crashes program if swapUp() is ever called
    }
    return result;
}
template <typename T>
int PriorityQueue<T>::getPriority(int n){
    int result;
    if(isEmpty()){
        std::cout << "nnWARNING: Trying to get priority from empty queuenn";
        result = -1;
    } else if( n < 0 || n > size){
        std::cout << "nnWARNING: Trying to get priority from non-existent index " << n << "nn";
        result = -1;
    } else{
        Node * thisNode = head;
        for(int k = 0; k < n; k++)
            thisNode = thisNode -> prev;
        result = thisNode -> priority;
    }
    return result;
}
template <typename T>
void PriorityQueue<T>::display(){
    if(isEmpty()){
        std::cout << "nQueue is emptyn";
    } else {
        std::cout << "nINDEXtDATAtPRIORITYn";
        std::cout << "-----------------------n";
        Node * thisNode = head;
        for(int n = 0; n < size; n++){
            std::cout << n << "t" << thisNode->data << "t" << thisNode->priority << "n";
            thisNode = thisNode -> prev;
        }
        std::cout << "n";
    }
}

template <typename T>
void PriorityQueue<T>::revDisplay(){
    if(isEmpty()){
        std::cout << "nQueue is emptyn";
    } else {
        std::cout << "nINDEXtDATAtPRIORITYn";
        std::cout << "-----------------------n";
        Node * thisNode = tail;
        for(int n = 0; n < size; n++){
            std::cout << n << "t" << thisNode->data << "t" << thisNode->priority << "n";
            thisNode = thisNode -> next;
        }
        std::cout << "n";
    }
}

template <typename T>
void PriorityQueue<T>::swapUp(Node * target){
    if(target == head)
        return;
    Node * partner = target->next;
    if(partner == head){
        head = target;
        target->next = 0;
    } else
        target->next = partner->next;
    if(target == tail){
        tail = partner;
        partner->prev = 0;
    } else
        partner->prev = target->prev;
}
template <typename T>
bool PriorityQueue<T>::contains(T data){
     bool result = false;
     if(!isEmpty()){
        Node * thisNode = head;
        for(int n = 0; n < size; n++){
            if(thisNode->data == data){
                result = true;
                break;
            }
            thisNode = thisNode -> prev;
        }
    }
    return result;
}
template <typename T>
PriorityQueue<T>::~PriorityQueue(){
    clearQueue();
}
#endif

测试程序:

#include <iostream>
#include <string>
#include <ctype.h>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include "PriorityQueue.hpp"
int main(){
        PriorityQueue<char> test;
        test.enqueue('c',1);
        test.enqueue('a',2);
        test.enqueue('t',3);
        test.display();
        std::cout <<"nREVERSE:n";
        test.revDisplay();
        std::cout<<"nWITH SORTING:n";
        test.enqueue('d',5);
        test.enqueue('s',9);
        test.enqueue('g',7);
        test.enqueue('o',6);
        test.enqueue('&',4);
        test.display();
        std::cout <<"nnALL DONEnn";
        return 0; 
}

好的,所以我尝试以两种不同的新方式实现 SwapUp(),这两种方式仍然给我带来错误。

失败的尝试 #1:

template <typename T>
void PriorityQueue<T>::swapUp(Node * target){
    Node * partner = target->next;    //Partner = target next
    Node * temp = new Node;   // temp spot to hold partner neighbors
    temp->next = partner->next;
    temp->prev = partner->prev;
    partner->next = target->next;
    partner->prev = target->prev;
    target->next = temp->next;
    target->prev = temp->prev;
    if(target == tail)
        tail = partner;
    if(partner == head)
        head = target;
    delete temp;
}

失败的尝试 #2:

template <typename T>
void PriorityQueue<T>::swapUp(Node * target){
    Node * partner = target->next;    //Partner = target next
    target->next = partner->next;   //Target next = partner next
    partner->prev = target->prev;   //Partner prev = target prev
    partner->next = target;          //Partner next = target
    target->prev = partner;           //Target prev = partner
    if(target == tail)
        tail = partner;
    if(partner == head)
        head = target;
}

这让我非常生气。这是一个如此基本的逻辑问题,我不知道为什么我会遇到这么多麻烦。任何帮助将不胜感激!

swapUp中,你有一些问题。 永远不会调用解决if(partner == head)的子句,因为您已经返回了 if target == head。

swapUp 不会设置要交换的两个值的反向上一个和下一个指针,只会设置目标的next和下一个节点的prev。 上一个和下一个都需要交换以维护您的双向链表。