双向链表:前面没有插入值

时间:2013-02-02 13:14:25

标签: c++ data-structures doubly-linked-list

这是一个DLinkedList实现,使用addFront()添加了int类型的元素,但是没有使用front()检索它。没有显示错误。不知道为什么?这是完整的实施。代码在xCode4.5上运行。

int main(int argc, const char * argv[])
{
    DLinkedList listOne;

    if(listOne.empty()){
        cout<<"Empty";
    }
    const int num=23;
    listOne.addFront(num);

    //Here 0 is returned from front(), while it should be 23;
    cout<<listOne.front()<<endl;

    return 0;
}

//Node Defination
class DNode {                   // doubly linked list node
private:
    int elem;                   // node element value
    DNode* prev;                // previous node in list
    DNode* next;                // next node in list
    friend class DLinkedList;           // allow DLinkedList access
};

class DLinkedList {             // doubly linked list
public:
    DLinkedList();              // constructor
    ~DLinkedList();             // destructor
    bool empty() const;             // is list empty?
    const int front() const;            // get front element
    const int back() const;         // get back element
    void addFront(const int e);     // add to front of list
    void addBack(const int e);      // add to back of list
    void removeFront();             // remove from front
    void removeBack();              // remove from back
private:                    // local type definitions
    DNode* header;              // list sentinels
    DNode* trailer;
protected:                  // local utilities
    void add(DNode* v, const int e);        // insert new node before v
    void remove(DNode* v);          // remove node v
};

void listReverse(DLinkedList& L) {      // reverse a list
    DLinkedList T;              // temporary list
    while (!L.empty()) {            // reverse L into T
        int s = L.front();  L.removeFront();
        T.addFront(s);
    }
    while (!T.empty()) {            // copy T back to L
        int s = T.front();  T.removeFront();
        L.addBack(s);
    }
}

void DLinkedList::remove(DNode* v) {        // remove node v
    DNode* u = v->prev;             // predecessor
    DNode* w = v->next;             // successor
    u->next = w;                // unlink v from list
    w->prev = u;
    delete v;
}

void DLinkedList::removeFront()     // remove from font
{ remove(header->next); }

void DLinkedList::removeBack()      // remove from back
{ remove(trailer->prev); }

// insert new node before v
void DLinkedList::add(DNode* v, const int e) {
    DNode* u = new DNode;  u->elem = e;     // create a new node for e
    std::cout<<u->elem<<std::endl;
    u->next = v;                // link u in between v
    u->prev = v->prev;              // ...and v->prev
    v->prev->next = v->prev = u;
}

void DLinkedList::addFront(const int e) // add to front of list
{
    add(header->next, e);
}

void DLinkedList::addBack(const int e)  // add to back of list
{ add(trailer, e); }

DLinkedList::~DLinkedList() {           // destructor
    while (!empty()) removeFront();     // remove all but sentinels
    delete header;              // remove the sentinels
    delete trailer;
}

DLinkedList::DLinkedList() {            // constructor
    header = new DNode;             // create sentinels
    trailer = new DNode;
    header->next = trailer;         // have them point to each other
    trailer->prev = header;
    std::cout<<"DLinkedListConstructor"<<std::endl;
}

bool DLinkedList::empty() const     // is list empty?
{ return (header->next == trailer); }

const int DLinkedList::front() const    // get front element
{ return header->next->elem; }

const int DLinkedList::back() const     // get back element
{ return trailer->prev->elem; }

3 个答案:

答案 0 :(得分:3)

问题在于您的add功能:

// insert new node before v
void DLinkedList::add(DNode* v, const int e) {
    DNode* u = new DNode;  u->elem = e;     // create a new node for e
    std::cout<<u->elem<<std::endl;
    u->next = v;                // link u in between v
    u->prev = v->prev;              // ...and v->prev
    v->prev->next = v->prev = u;
}

让我们来完成。您从以下情况开始(我称之为v->prev指向p的节点):

┌───────────┐
│           ▼
p ◀──────── v

      u

然后,您将u->next设置为v

┌───────────┐
│           ▼
p ◀──────── v
            ▲
      u─────┘

然后u->prev改为v->prev

┌───────────┐
│           ▼
p ◀──────── v
▲           ▲
└─────u─────┘

下一行是问题所在。首先,它将u分配给v->prev

┌───────────┐
│           ▼
p     ┌──── v
▲     ▼     ▲
└─────u─────┘

然后它为v->prev->next分配相同的指针。但v->prev现在是u,因此您只需将u->next设置为v即可。所以没有变化。

现在当你尝试获取前面的元素时,你只是得到元素v,这是你的前哨节点。

您需要单独执行这两项任务:

v->prev->next = u;
v->prev = u;

答案 1 :(得分:2)

首先,您没有初始化所有节点的prevnext指针。构造列表时,列表的构造函数会执行:

header = new DNode;             // create sentinels
trailer = new DNode;
header->next = trailer;         // have them point to each other
trailer->prev = header;

这意味着header->prevtrailer->next未初始化。这些指针不会自动初始化为NULL,所以要小心。

但是你所观察到的根本原因是你的add_front()函数中,你正在调用一个add()函数,最终会这样做:

// Replacing v with header->next, which is the actual argument of the call
...
u->next = header->next;          // u->next = trailer      
u->prev = header->next->prev;    // u->prev = trailer->prev; // Uninitialized!
header->next->prev = u;          // trailer->prev = u;
header->next->prev->next = u;    // u->next = u

由于最后一个陈述,这显然是错误的,因为你永远不会分配header->next = u

是的,我建议你考虑使用智能指针而不是原始指针,根据所需的所有权语义进行适当的选择。除此之外,智能指针会自动初始化为nullptr

答案 2 :(得分:1)

代码在Windows中的Mingw Compiler上运行得很好,使用代码块给出了23而不是0。 但是,我建议进行以下更改,因为有些编译器会从右到左分配值,堆栈事物......

void DLinkedList::add(DNode* v, const int e) {
    DNode* u = new DNode;  u->elem = e;     // create a new node for e
    std::cout<<u->elem<<std::endl;
    u->next = v;                // link u in between v
    u->prev = v->prev;              // ...and v->prev
    v->prev->next = u;              // do this first......
    v->prev = u;                    // then this.
}