【问题标题】:Search in a Doubly-Linked List founds members multiple times在双向链表中搜索多次找到成员
【发布时间】:2021-07-06 16:00:19
【问题描述】:

我正在完成 PPPC++ 的练习,我有一个 List 类,其中包含多个神及其属性。

例如:{Thor, Norse, Chariot, Mjolnir} 或 {Hera, Greek, chariot, pomegranate} 其中托尔是北欧神,赫拉是希腊神。

我正在尝试编写代码来找到指向所有希腊神灵的指针。

而且我不明白为什么赫拉会被发现两次,而阿瑞斯会被发现 4 次。 怎么了? 谢谢!

found 0x5586b65353f0 Poseidon
found 0x5586b6535350 Athena
found 0x5586b65351d0 Hera
found 0x5586b65351d0 Hera
found 0x5586b6534f50 Ares
found 0x5586b6534f50 Ares
found 0x5586b6534f50 Ares
found 0x5586b6534f50 Ares
found 0x5586b6534eb0 Zeus

代码是:

#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;

struct God
{
    God(const string &n, const string &m, const string &v, const string &w)
        : name{n}, mythology{m}, vehicle{v}, weapon{w} {}

    string name;
    string mythology;
    string vehicle;
    string weapon;
};

class Link
{
public:
    God god; 
    Link(const string &n, const string &m, const string &v, const string &w, Link *p = nullptr, Link *s = nullptr)
        : god{n, m, v, w}, prev{p}, succ{s} {}
    Link *insert(Link *n);                 // insert n before this object
    Link *find_mythology(const string &s); // find s in list

    Link *next() const { return succ; }
    Link *previous() const { return prev; }

private:
    Link *prev;
    Link *succ;
};

Link *Link::insert(Link *n) // insert n before this object; return n
{
    if (n == nullptr)
        return this;
    if (this == nullptr)
        return n;
    n->succ = this;     // this object comes after n
    if (prev)           // if prev of this (object) is not zero - meaning there's a Link object before this object (or p)
        prev->succ = n; // perv->succ
    n->prev = prev;     // this object’s predecessor becomes n’s predecessor
    prev = n;           // n becomes this object’s predecessor
    return n;           // returns n(the new element) which is before the top node
}
Link *Link::find_mythology(const string &s) // find s in list;
{
    Link *p = this;
    while (p)
    {
        if (p->god.mythology == s)
            return p;
        p = p->succ; // move to the next node
    }
    return nullptr; // return nullptr for “not found”
}
void print_all(Link *p)
{
    while (p)
    {
        cout << " " << p->god.name << ", " << p->god.mythology << ", " << p->god.vehicle << ", " << p->god.weapon;
        if (p = p->next()) // moved to the next node
            cout << "\n";
    }
}

int main()
{
    Link *all_gods = new Link{"Zeus", "Greek", "chair", "lightning"};
    all_gods = all_gods->insert(new Link{"Ares", "Greek", "wings", "sword"});
    all_gods = all_gods->insert(new Link{"Odin", "Norse", "Sleipner", "Gungnir"});
    all_gods = all_gods->insert(new Link{"Thor", "Norse", "Chariot", "Mjolnir"});
    all_gods = all_gods->insert(new Link{"Freia", "Norse", "chariot", "Brisingamen"});
    all_gods = all_gods->insert(new Link{"Hera", "Greek", "chariot", "pomegranate"});
    all_gods = all_gods->insert(new Link{"Tyr", "Norse", "chariot", "spear of justice"});
    all_gods = all_gods->insert(new Link{"Athena", "Greek", "chariot", "thunderbolt"});
    all_gods = all_gods->insert(new Link{"Poseidon", "Greek", "the sea", "trident"});

    print_all(all_gods); // cout the type of the 1st element
    cout << "\n\n";

//while (all_gods)
//{
//    Link *p = all_gods->find_mythology("Greek"); // this returns a pointer where it finds a Norse
//     cout << "found " << p << ' ' << p->god.name << '\n';
//   all_gods = all_gods->next();
//}

Link *p = all_gods;
while (p)
{
    if (p->god.mythology == "Greek")
        cout << "found " << p << ' ' << p->god.name << '\n';
    p = p->next();
}
delete[] p;
// here I will still use all_gods before deleting it below
delete all_gods;

print_all(all_gods);
cout << "\n\n";
print_all(p);
cout << "\n\n";
}

编辑

我更改了 main() 中的 while 循环,现在它可以执行我想要的操作了。

【问题讨论】:

  • this == nullptr 永远不会是真的。
  • 你从第一个元素开始寻找第一个“希腊语”,然后从第二个元素开始,然后从第三个元素开始,......如果第三个元素是第一个“希腊语”,你会找到多少次?
  • all_gods = all_gods-&gt;next(); -- 祝你好运尝试delete 分配的所有内容。
  • 如果最后一个元素不是您要查找的内容,您就有麻烦了,因为p 将是空指针。

标签: c++ doubly-linked-list


【解决方案1】:

你的代码看起来不错(虽然不是很OO)。

它似乎也以我期望的方式工作:

// When you start the list is:
//    Poseidon : Athena : Tyr : Hera ......
while (all_gods)
{
    // So first time threw this loop you find: Poseidon
    Link *p = all_gods->find_mythology("Greek");
    cout << "found " << p << ' ' << p->god.name << '\n';

    // Now you are altering the list (and leaking an object.
    // but thats another question).
    //
    
    all_gods = all_gods->next();
    // But you dropped "Poseidon" off the front so the list is now:
    // Athena : Tyr : Hera ......
}

所以你第二次在循环中打印Athena。然后从列表中删除 Athena,因此列表为 Tyr : Hera ......

所以你第三次循环你将打印Hera(第一个希腊神)。但是你删除了Tyr,所以列表是Hera ......

所以第四次循环时,您将再次打印Hera,因为她仍然在名单上,并且是第一位希腊神。

【讨论】:

  • 谢谢马丁!我想我用一个新的while循环和一个新的指针修复了它(编辑了主帖),然后我删除了它。我不介意问更多问题...我应该如何使它更面向对象?
  • @Theodore A List 是一个对象。列表中的Link 是自己的对象,但与列表分开。您不会在您对列表执行insert() 的链接上执行insert()。你也没有资源管理没有。链接集没有所有权,您似乎只是通过指针传递所有权。 Links 的集合应该由 List 对象拥有和管理。当您 find() 不返回 Link 时,返回 God 引用。停止使用指针(我们在 C++ 中做的不多(了解所有权语义(共享指针和容器))。
  • 谢谢马丁!我正在学习 B. Stroustrup 书中的练习。希望再读 4 章后,我会比现在知道的更多。
猜你喜欢
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 2015-07-13
  • 2012-07-15
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多