【问题标题】:How to add and return a node in front of the linked list如何在链表前面添加和返回一个节点
【发布时间】:2018-04-11 18:52:23
【问题描述】:

虽然我正在使用linked_list 制作一个小游戏。我有一张班级电话卡

class card
{
public:
    int number;
    int suit;
    static int uniquenumber;
    card();
    void showcard();
    card * next;
};

那么对于下面的linked_list结构,我想把卡片加到linked_list的前面。

void collection::add(card a)
{
    card *temp = new card(a);
    temp->next = start;
    start = temp;
}

但我无法得到我想要的结果。此外,还有另一个功能需要从linked_list 的前面删除一张卡片,然后返回卡片。我不知道如何从linked_list 返回一个节点。

card collection::deal(){
card *temp = start->next;
start->next = nullptr;
start = temp;
return start;
}

这种方式只会给我一个错误提示“无法将“card *”转换为“card””

【问题讨论】:

    标签: c++ pointers linked-list


    【解决方案1】:

    添加

    演练时间:

    void collection::add(card a) // pass by value. a is a copy 
    {
        card *temp = new card(a); // makes a dynamically allocated copy of the copy.
        temp->next = start; // looks right
        start = temp; // looks right
    }
    

    这个函数没有明显的错误,但是如果你愿意的话

    myCollection.add(mycard);
    

    然后期望使用mycard 就好像它在myCollection 中一样,那么你就不走运了。 mycard 的副本位于 mycollection。我们可以做些小改进来减少复制量,

    void collection::add(const card & a) // pass by reference. a is the source. One less copy
                                         // Look up const correctness for more information 
                                         // on the use of const here 
    {
        card *temp = new card(a); // makes a dynamically allocated copy of the copy.
        temp->next = start; 
        start = temp;
    }
    

    但如果您希望 mycard 出现在列表中而不是其中的一部分,您需要以非常不同的方式做事

    void collection::add(card * a) // pass by reference via a pointer
    {
        a->next = start;
        start = a;
    }
    

    并像这样使用它:

    card * mycard = new card()
    // set members of *mycard. Or better, make a smarter constructor to set them for you
    myCollection.add(mycard);
    

    删除

    card collection::deal(){
        card *temp = start->next; //temp points to the second item on the list
        start->next = nullptr; // cur off start from the rest of the list
        start = temp; // whups! Just lost the first item in the list
        return start; // start is a pointer. The return type is not. Need to dereference
    }
    

    修复一个:尊重指针以返回它。

    card collection::deal(){
        card *temp = start->next; 
        start->next = nullptr; 
        start = temp; 
        return *start; // returns a copy of the second card in the list
    }
    

    下一个修复:返回正确的卡

    card collection::deal(){
        card *temp = start; //temp points to the first item on the list
        start = start->next; // advance start to second item on the list
        temp->next = nullptr; // cut former first item off from from the list
        return *temp; // returns a copy of the former first item. But what of temp?
    }
    

    下一个修复:temp 被泄露。没有人指向它,内存从未被释放。

    card collection::deal(){
        card *temp = start; 
        start = start->next; 
        temp->next = nullptr; 
        card rval(*temp); // copy former first node
        delete temp; // free former first node
        return rval; // return copy.
    }
    

    您还可以返回指向已删除项目的指针并将其释放给调用者。这有点狡猾。

    card * collection::deal(){
        card *temp = start; //temp points to the first item on the list
        start = start->next; // advance start to second item on the list
        temp->next = nullptr; // cut former first item off from from the list
        return temp; // returns former first item 
    }
    

    Look into std::unique_ptr 作为一个工具来确保返回的card 指针被调用者释放。

    另一种可能是将链表与card 分开,这样collection 的用户只能看到cards,不知道cards 是如何存储在collection 中的。

    【讨论】:

    • add()的第一次重写中,为什么要通过非const ref传递参数?
    • 感谢您的修复,雷米。 @bipll我不想打开另一罐蠕虫来解释一些切向的原因和方式。我觉得我已经有太多事情要做了,所以我只留下了一个关键术语的评论,如果他们有兴趣,提问者可以查看。
    • 再想一想,你是对的@bipll。解释可以是任何一种方式,所以我最好使用const 并建议他们自己查找原因。
    【解决方案2】:

    您的add() 看起来不错,但您的deal() 完全错误。它应该看起来更像这样:

    card collection::deal()
    {
        if (!start) throw std::runtime_error("deck is empty!");
        card *temp = start;
        start = temp->next;
        card theCard = *temp;
        c.next = nullptr;
        delete temp;
        return theCard;
    }
    

    您可以通过使用一些更有创意的编码来稍微简化代码,例如:

    class card
    {
    public:
        int number;
        int suit;
        card * next;
    
        static int uniquenumber;
    
        card();
        card(const card &src, card *n = nullptr);
        card& operator=(const card &rhs);
    
        void showcard();
    };
    

    #include <memory>
    
    card::card()
        : number(0), suit(0), next(nullptr)
    {
    }
    
    card::card(const card &src, card *n)
        : number(src.number), suit(src.suit), next(n)
    {
    }
    
    card& card::operator=(const card &rhs)
    {
        if (&rhs != this)
        {
            number = rhs.number;
            suit = rhs.suit;
            // don't copy 'next'!
            next = nullptr;
        }
        return *this;
    }
    
    void collection::add(const card &a)
    {
        start = new card(a, start);
    }
    
    card collection::deal()
    {
        if (!start) throw std::runtime_error("deck is empty!");
        std::unique_ptr<card> temp(start);
        start = start->next;
        return *temp;
    }
    

    但是,话虽如此,从设计的角度来看,card 根本不应该有next 成员。您应该将card 与链表的实现分开(这反过来又允许您在以后更改列表的实现,而无需更改card 以匹配)。您需要一个包含卡片对象的列表,而不是一个卡片对象的列表。

    您应该使用std::list 进行分隔,例如:

    #include <list>
    
    class card
    {
    public:
        int number;
        int suit;
    
        static int uniquenumber;
    
        card();
        void showcard();
    };
    
    class collection
    {
    private:
        std::list<card> cards;
    
    public:
        void add(const card &a);
        card deal();
    };
    

    void collection::add(const card &a)
    {
        cards.push_front(a);
    }
    
    card collection::deal()
    {
        if (cards.empty()) throw std::runtime_error("deck is empty!");
        card theCard = cards.front();
        cards.pop_front();
        return theCard;
    }
    

    但是,如果你不能使用std::list,那么你可以使用类似这样的东西:

    class card
    {
    public:
        int number;
        int suit;
    
        static int uniquenumber;
    
        card();
        void showcard();
    };
    
    class collection
    {
    private:
        struct collectionItem
        {
            card theCard;
            collectionItem *next;
    
            collectionItem(const card &a, collectionItem *n);
        };
    
        collectionItem *start;
    
    public:
        collection();
        ~collection();
    
        void add(const card &a);
        card deal();
    };
    

    #include <memory>
    
    collection::collection()
        : start(nullptr)
    {
    }
    
    collection::collectionItem::collectionItem(const card &a, collectionItem *n)
        : theCard(a), next(n)
    {
    }
    
    collection::~collection()
    {
        collectionItem *item = start;
        while (item)
            item = std::unique_ptr<collectionItem>(item)->next;
    }
    
    void collection::add(const card &a)
    {
        start = new collectionItem(a, start);
    }
    
    card collection::deal()
    {
        if (!start) throw std::runtime_error("deck is empty!");
        std::unique_ptr<collectionItem> temp(start);
        start = temp->next;
        return temp->theCard;
    }
    

    【讨论】:

      【解决方案3】:

      如果你有指针变量,你可以得到指针解引用指针所引用的实际值。

      试试return *start;

      【讨论】:

      • 这不满足给定的要求:“从linked_list的前面移除一张卡片,并返回卡片”。如果您只是 return 取消引用的指针,则不会从列表中删除 card。如果你从列表中删除card,你仍然要销毁它,所以你不能取消引用它并同时销毁它。您必须制作card副本,销毁列表中的card,然后return 副本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 1970-01-01
      • 2019-12-16
      相关资源
      最近更新 更多