重载用于添加两个双链表的运算符

Overloading operators for adding two doubly linked lists

本文关键字:两个 链表 运算符 用于 添加 重载      更新时间:2023-10-16

我需要帮助重载'+'运算符,以便将两个双链表添加在一起。由于出现"运算符=…不匹配"错误,我无法编译程序。我已经重载了"="运算符,但很难将添加的结果打印到std输出中。我还使<lt;操作人员几个小时以来,我一直试图找出问题所在,但没有成功。任何关于如何解决这个问题和/或解决方案的提示都是非常受欢迎的。这是我OOP课的作业。提前感谢!

编辑:代码背后的基本思想是复制集合。重载运算符"+"应作为并集,"*"应作为交集。我很难将并集正确打印到std输出。'+='看来效果不错<lt;'效果也很好,但只有在打印单个列表时。


编辑:编译器产生的错误(g++,从代码输出::块,我删除了编译器注释):

llist3.cpp|149|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note:   no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|151|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note:   no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|152|error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka       std::basic_ostream<char>}’ and ‘LList’)|

   #include<iostream>
using namespace std;
class LList {
public:
    struct Node {
        int elem;
        Node* succ;
        Node* prev;
        Node() : succ(0), prev(0), elem(0) {}
    };
    LList();
    LList(LList& list);
    ~LList();
    Node* next();
    Node* begin()  { curr = head; }
    int getElem() { return curr->elem; }
    void addElem(int elem);
    LList operator+(LList& set);
    LList operator+(int elem);
    LList& operator+=(LList& set);
    LList& operator+=(int elem);
    LList& operator=(LList& list);
    friend ostream& operator<<(ostream& os, LList& obj);
 private:
    Node* curr;
    Node* head;
    Node* tail;
    int size;
    void pushFront(Node* n);
    void pushInside(Node* n);
    void pushBack(Node* n);
};
LList::LList() : head(0), tail(0), size(0), curr(0) {}
LList::LList(LList& list) : size(0), curr(0), head(0), tail(0) {
    list.curr = list.head;
    while(list.curr) {
        addElem(list.getElem());
        list.next();
    }
}
LList::Node* LList::next() {
    if (curr)
        return (curr = curr->succ);
    else
        return 0;
}
void LList::addElem(int elem) {
    Node* n = new Node;
    n->elem = elem;
    if (curr) {
        if (curr == head && elem < curr->elem) {
            pushFront(n);
        }
        else if (elem > curr->elem) {
            curr = curr->succ;
            addElem(elem);
        }
        else if (elem < curr->elem && elem > (curr->prev)->elem) {
            pushInside(n);
        }
        else if (elem < curr->elem) {
            curr = curr->prev;
            addElem(elem);
        }
    } else {
        pushBack(n);
    }
}
void LList::pushFront(Node* n) {
    head = n;
    n->succ = curr;
    curr->prev = n;
    n->prev = 0;
    curr = n;
    size++;
}
void LList::pushInside(Node* n) {
    (curr->prev)->succ = n;
    n->succ = curr;
    n->prev = curr->prev;
    curr->prev = n;
    size++;
}
void LList::pushBack(Node* n) {
    if (!head) {
        head = n;
    } else {
        tail->succ = n;
        n->prev = tail;
    }
    tail = n;
    curr = n;
    size++;
}
LList::~LList() {
    for (curr = head; curr;) {
        Node* temp = curr->succ;
        delete curr;
        curr = temp;
    }
}
LList& LList::operator=(LList& list) {
    list.begin();
    if (this != &list) {
        for (curr = head; curr;) {
            Node* temp = curr->succ;
            delete curr;
            curr = temp;
        }
        while (list.curr) {
            addElem(list.getElem());
            list.next();
        }
    }
    return *this;
}
ostream& operator<<(ostream& os, LList& list) {
    LList::Node* p = list.head;
    os << "{ ";
    while(p) {
        os << p->elem << (p->succ ? ", " : "");
        p = p->succ;
    }
    os << " }" << endl;
    return os;
}
LList LList::operator+(LList& set) {
    LList temp = *this;
    temp += set;
    return temp;
}
LList LList::operator+(int elem) {
    *this += elem;
    return *this;
}
int main() {
    LList setA;
    setA.addElem(1234);
    setA.addElem(1435);
    setA.addElem(1100);
    LList setB;
    setB.addElem(1234);
    setB.addElem(1435);
    setB.addElem(5100);
    setB = setA + 1234; // 1st error here
    LList setD;
    setD = setA + setB; //2nd
    cout << setA + setB << endl; //3rd
}

您的代码中有一个明显的错误:

Node* begin()  { curr = head; }

此代码调用未定义的行为,因为您没有返回值。应该是这样的:

Node* begin()  { curr = head; return curr; }

此外,您应该在不更改LList参数的函数中通过const引用传递LList

例如:

LList::LList(LList& list);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);

应该是:

LList::LList(const LList& list);
LList& operator=(const LList& list);
friend ostream& operator<<(ostream& os, const LList& obj);

请更改这些函数和其他函数以传递常量引用。如果你想知道为什么你应该改变这一点,如果你试图这样做,你会立即看到问题:

LList list1;
LList list2;
//...
std::cout << list1 + list2;

operator <<正在寻找非常量的LList对象,但添加的"inline"返回一个临时LList(这意味着返回值将是const)。由于重载的operator <<只接受非常数LList,因此代码将不会编译。

因此,您需要将operator <<中的参数更改为const LList&

您的列表类中有一个内置的"current"指针。这是一个严重的设计错误。由于此错误,您无法正确定义函数。

这是一个设计错误,因为使用此设计,您无法对const列表进行迭代,这意味着,除了其他不好的事情外,您无法使用临时列表做任何有用的事情。因此,当你计算setA + setB时,你不能把它分配给任何东西,因为要分配,你需要迭代,所以你需要给operator=和复制构造函数一个非常量参数。但是,不能将临时引用绑定到非常量引用。

即使绕过复制构造函数和复制赋值运算符中的公共接口,在不使用curr的情况下直接复制列表,任何必须使用公共接口的用户函数也会遇到同样的问题。也就是说,setA + setB将不能用作函数参数。您需要先将其分配给某个变量,然后将该变量传递给函数。

您也不能在迭代过程中获取列表并将其传递给某个函数,并期望从您留下的位置继续迭代,因为任何迭代列表的操作都会更改curr指针。

最好的解决方案是去掉curr成员,并使您的大部分论点成为const LList&。虽然这不是onky解决方案,但将当前指针构建到列表类中还有许多其他缺点,所以我不讨论它们。

为了迭代列表,您必须提供一个可以在列表上来回移动的单独对象,以及一个可在const列表上来回旋转的单独变体。这被称为迭代器,如果你想在C++中做任何事情,你需要了解这个概念。

在您的情况下,迭代器可以是Node*const Node*。您只需要提供返回列表中第一个节点的成员函数,该节点已经存在。真正的图书馆也是如此。由于各种原因,它们通常将节点指针封装在一个单独的迭代器类中;但对于一个简单的家庭作业来说,这是不必要的(尽管如果你愿意,你可以做)。