如何在节点中返回数据?

时间:2019-03-25 16:32:42

标签: c++ c++11 linked-list

我必须在GetHead()GetTail()中返回列表的开头和结尾。

我试图自己返回头部和尾巴并得到错误:

cannot initialize return object of type 'int' with an lvalue of type 'Node<int> *const'
    return tail;

我还尝试返回head->valuetail->value,它在EXC_BAD_ACCESS中给了string() const


template<typename T>
class Node
{
private:
    T value;
    Node* prev;
    Node* next;
public:
    Node(T value, Node* prev = NULL, Node* next = NULL);
    friend class List<T>;
};

template<typename T>
class List
{
private:
    Node<T>* head;
    Node<T>* tail;
public:
    List();
    List(const List<T>& src);
    ~List();
    bool IsEmpty() const;
    T GetHead() const;
    T GetTail() const;
    void AddToHead(T v);
    void AddToTail(T v);
    bool RemoveHead();
    bool RemoveTail();

    operator string() const;
    ///////////////////////////////////////////
    // Do not change the above prototype.
    // Add member function(s) below if you need.

    // Do not change the below.
    ///////////////////////////////////////////
};

template<typename T>
Node<T>::Node(T value, Node* prev, Node* next)
{
    this->value = value;
    this->prev = prev;
    this->next = next;
}

template<typename T>
List<T>::operator string() const
{
    if (IsEmpty())
        return "()";
    stringstream os;
    os << "(";
    Node<T>* r = head;
    while (r != tail)
    {
        os << r->value << ",";
        r = r->next;
    }
    os << r->value << ")";
    string str = os.str();
    return str;
}

template<typename T>
List<T>::List()
{
    // make list empty
    head = tail = NULL;
}

template<typename T>
List<T>::List(const List<T>& src)
{
    // make list empty
    head = tail = NULL;

    // copy all contents in src into this
    Node<T>* node = src.head;
    while(node != NULL)
    {
        AddToTail(node->value);
        node = node->next;
    }
}

template<typename T>
bool List<T>::IsEmpty() const
{
    return (head == NULL);
}

///////////////////////////////////////////
// Do not change the above.
// Implement your own member functions below.

template<typename T>
List<T>::~List()
{
    while (!IsEmpty())
        RemoveTail();
}

template<typename T>
void List<T>::AddToTail(T v)
{
    if (IsEmpty())
        head = tail = new Node<T>(v, NULL, NULL);
    else
    {
        head = new Node<T>(v, tail, NULL);
        head->prev->next = tail;
    }
}

template<typename T>
void List<T>::AddToHead(T v)
{
    if (IsEmpty())
        head = tail = new Node<T>(v, NULL, NULL);
    else
    {
        head = new Node<T>(v, NULL, head);
        head->next->prev = head;
    }
}

template<typename T>
bool List<T>::RemoveHead()
{
    if(IsEmpty())
        return false;

    if(head == tail)
    {
            delete tail;
            head = tail = NULL;
            return true;
    }
    else
    {
        head = head->next;
        delete head->prev;
        head->prev = NULL;
        return true;
    }
}

template<typename T>
bool List<T>::RemoveTail()
{
    if(IsEmpty())
        return false;

    if(head == tail)
    {
        delete tail;
        head = tail = NULL;
        return true;
    }
    else
    {
        tail = tail->prev;
        delete tail->next;
        tail->next = NULL;
        return true;
    }
}

template<typename T>
T List<T>::GetHead() const
{
    return head;
}

template<typename T>
T List<T>::GetTail() const
{
    return tail;
}

1 个答案:

答案 0 :(得分:1)

您自己不能返回head / tail,因为返回类型为T,所以您必须返回内容。

关于使用EXC_BAD_ACCESS时为何在string() const中得到->value的问题,AddToTail中存在一个主要问题。如果您仅添加了一个元素,则headtail是同一指针,其中prev的{​​{1}}和next。然后,您可以这样做:

NULL

使用 head = new Node<T>(v, tail, NULL); 的{​​{1}}和prev的{​​{1}}组成一个新元素,并将该新元素设为新的tail(因此因为next替换了NULL?!?),所以有些奇怪。

下一步

head

采用新元素,找到它的AddToTail(当前的head /旧的 head->prev->next = tail; )并说其prevtail。因此,新的head的{​​{1}}的{​​{1}}(从未设置),next的{​​{1}}和tail本身都有一个head本身(因此,如果您从next返回,然后再尝试前进,则会陷入无限循环)。

来自NULL的无限循环甚至不是这里的问题。问题是来自prev的{​​{1}}路径命中tail却从未见过tail。如果您尝试next,它将从head开始并继续tail,直到达到next(如果列表构造正确,这是一个合理的假设)。但它从未到达head,只是碰到NULL并死于试图读取tail,这显然是坏的。

您需要修复operator string(),以便创建合法的head。并可能在向next遍历的代码中添加tail,以寻找tail来验证它在命中NULL之前没有命中NULL->value。我相信解决方法是将AddToTail的{​​{1}}大小写更改为:

List

但一定要重新检查您的逻辑并在可能的情况下适当添加assert