C ++链接列表赋值:插入和删除有问题

时间:2011-10-10 18:16:00

标签: c++ algorithm linked-list

我正在研究C ++中的链表实现。我正在取得进展,但我无法使插入功能和删除功能正常工作。下面是C ++头文件中的列表对象:

#ifndef linkList_H
#define linkList_h


//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
    Node() : sentinel(0) {}

    int number;
    Node* next;
    Node* prev;
    Node* sentinel;
};


//
// Create an object to keep track of all parts in the list
//
class List
{
public:

    //
    // Contstructor intializes all member data
    //
    List() : m_listSize(0), m_listHead(0) {}

    //
    // methods to return size of list and list head
    //
    Node*    getListHead() const { return m_listHead; }
    unsigned getListSize() const { return m_listSize; }

    //
    // method for adding and inserting a new node to the linked list, 
    // retrieving and deleting a specified node in the list
    //
    void  addNode(int num);
    void  insertNode(Node* current);
    void  deleteNode(Node* current);

    Node* retrieveNode(unsigned position);

private:

    //
    // member data consists of an unsigned integer representing
    // the list size and a pointer to a Node object representing head
    //
    Node*    m_listHead;
    unsigned m_listSize;
};

#endif

这是实现(.cpp)文件:

#include "linkList.h"
#include <iostream>

using namespace std;


//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
    Node *newNode = new Node;
    newNode->number = num;
    newNode->next = m_listHead;
    m_listHead = newNode;
    ++m_listSize;
}


//
// NOTWORKING: Inserts a node which has already been set to front
// of the list
//
void List::insertNode(Node* current)
{
        // check to see if current node already at
        // head of list
    if(current == m_listHead)
        return;

    current->next = m_listHead;

    if(m_listHead != 0)
        m_listHead->prev = current;

    m_listHead = current;
    current->prev = 0;
}


//
// NOTWORKING: Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
    current->prev->next = current->next;
    current->next->prev = current->prev;
}


//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
    if(position > (m_listSize-1) || position < 0)
    {
        cout << "Can't access node; out of list bounds";
        cout << endl;
        cout << endl;

        exit(EXIT_FAILURE);
    }

    Node* current = m_listHead;
    unsigned pos = 0;

    while(current != 0 && pos != position)
    {
        current = current->next;
        ++pos;
    }

    return current;
 }

在客户端C ++代码中运行一个简短的测试程序后,结果输出如下:

Number of nodes: 10

Elements in each node:
9 8 7 6 5 4 3 2 1 0

Insertion of node 5 at the list head:
4 9 8 7 6 5 4 9 8 7

Deletion of node 5 from the linked list

如您所见,插入不仅仅是将节点5移动到列表头部,而是覆盖从第三个位置开始的其他节点。我试图实现的伪代码来自MIT算法书:

LIST-INSERT(L, x)
    next[x] <- head[L]
    if head[L] != NIL
        then prev[head[L]] <- x
    head[L] <- x
    prev[x] <- NIL

此外,删除实现只是在调用方法时崩溃。不确定为什么;但这里是相应的伪代码:

LIST-DELET'
    next[prev[x]] <- next[x]
    prev[next[x]] <- prev[x]

老实说,我不确定前一个,下一个和一些哨兵指针是如何在内存中工作的。我知道他们应该在实际意义上做什么,但看看调试器看起来这些指针在删除的情况下并没有指向任何东西:

(*current).prev 0xcdcdcdcd {number=??? next=??? prev=??? ...}   Node *
    number          CXX0030: Error: expression cannot be evaluated  
    next            CXX0030: Error: expression cannot be evaluated  
    prev            CXX0030: Error: expression cannot be evaluated  
    sentinel    CXX0030: Error: expression cannot be evaluated  

非常感谢任何帮助!!

3 个答案:

答案 0 :(得分:0)

addNode()出现错误。在你修复之前,你不能指望insertNode工作。

另外,我认为你的设计非常愚蠢。例如,一个名为“insertNode”的方法应该在任意位置插入一个新项,但是你的方法insertNode做了一个非常不同的事情,所以你应该重命名它。还应重命名addNode。同样,当glowcoder写道,为什么有那么多的哨兵?我担心你的班级设计整体上很糟糕。

实际错误是您忘记设置旧头的prev属性。它应该指向新的头脑。

void List::addNode(int num)
{
    Node *newNode = new Node;
    newNode->number = num;
    newNode->next = m_listHead;

    if(m_listHead) m_listHead->prev = newNode;

    m_listHead = newNode;
    ++m_listSize;
}

同样,deleteNode()还有另一个错误。从列表中删除最后一项时它不起作用。

void List::deleteNode(Node* current)
{
    m_listSize--;
    if(current == m_listHead) m_listHead = current->next;
    if(current->prev) current->prev->next = current->next;
    if(current->next) current->next->prev = current->prev;
}

现在你可以修复你所谓的insertNode:

void List::insertNode(Node* current)
{
    int value = current->number;
    deleteNode(current);
    addNode(value);
}

请注意,我在这里写了一切,没有在C ++编译器中编译和测试。也许有一些错误,但我希望它至少可以帮助你一点点。

答案 1 :(得分:0)

在deleteNode中,您不处理current-&gt; next和/或current-&gt; prev为null的情况。此外,如果当前恰好是头部,则不会更新列表头。

你应该这样做:

node* next=current->next;
node* prev=current->prev;

if (next!=null) next->prev=prev;
if (prev!=null) prev->next=next;

if (m_listhead==current) m_list_head=next;

(警告:我实际上没有测试过上面的代码 - 但我认为这足以说明我的想法)

我不确定您的InsertNode方法到底是什么,所以我无法在那里提供任何帮助。

答案 2 :(得分:0)

行。

  1. 正如@Al Kepp指出的那样,你的“添加节点”是错误的。看看Al的代码并修复它。

  2. 您正在执行的“插入”似乎不是正常的列表插入。相反,它似乎是一种“向前迈进”的行动。

  3. 尽管如此,您需要先将节点从列表中的当前位置删除,然后再将其添加到列表的开头。

  4. <强>更新

    我认为你误解了插入应该如何工作。它应该插入一个新节点,而不是列表中已有的节点。

    请参阅下面的一个简单示例。

    #include <iostream>
    
    // List Node Object
    //
    struct Node
    {
        Node(int n=0);
        int nData;
        Node* pPrev;
        Node* pNext;
    };
    
    Node::Node(int n)
    : nData(n)
    , pPrev(NULL)
    , pNext(NULL)
    {
    }
    
    //
    // List object
    //
    class CList
    {
    public:
    
        //
        // Contstructor 
        //
        CList();
    
        //
        // methods to inspect list
        //
        Node*    Head() const;
        unsigned Size() const;
        Node*    Get(unsigned nPos) const;
        void     Print(std::ostream &os=std::cout) const;
    
        //
        // methods to modify list
        //
        void Insert(int nData);
        void Insert(Node *pNew);
        void Delete(unsigned nPos);
        void Delete(Node *pDel);
    
    private:
        //
        // Internal data
        //
        Node*    m_pHead;
        unsigned m_nSize;
    };
    /////////////////////////////////////////////////////////////////////////////////
    CList::CList()
    : m_pHead(NULL)
    , m_nSize(0)
    {
    }
    Node *CList::Head() const 
    { 
        return m_pHead; 
    }
    unsigned CList::Size() const 
    { 
        return m_nSize; 
    }
    void CList::Insert(int nData)
    {
        Insert(new Node(nData));
    }
    void CList::Insert(Node *pNew)
    {
        pNew->pNext = m_pHead;
        if (m_pHead)
            m_pHead->pPrev = pNew;
        pNew->pPrev = NULL;
        m_pHead     = pNew;
        ++m_nSize;
    }
    void CList::Delete(unsigned nPos)
    {
        Delete(Get(nPos));
    }
    void CList::Delete(Node *pDel)
    {
        if (pDel == m_pHead)
        {
            // delete first
            m_pHead = pDel->pNext;
            if (m_pHead)
                m_pHead->pPrev = NULL;
        }
        else
        {
            // delete subsequent
            pDel->pPrev->pNext = pDel->pNext;
            if (pDel->pNext)
                pDel->pNext->pPrev = pDel->pPrev;
        }
        delete pDel;
        --m_nSize;
    }
    
    Node* CList::Get(unsigned nPos) const
    {
        unsigned nCount(0);
        for (Node *p=m_pHead; p; p = p->pNext)
            if (nCount++ == nPos)
                return p;
        throw std::out_of_range("No such node");
    }
    
    void CList::Print(std::ostream &os) const
    {
        const char szArrow[] = " --> ";
    
        os << szArrow;
        for (Node *p=m_pHead; p; p = p->pNext)
            os << p->nData << szArrow;
        os << "NIL\n";
    }
    
    int main()
    {
        CList l;
    
        l.Print();
    
        for (int i=0; i<10; i++)
            l.Insert((i+1)*10);
    
        l.Print();
    
        l.Delete(3);
    
        l.Delete(7);
    
        l.Print();
    
        try
        {
            l.Delete(33);
        }
        catch(std::exception &e)
        {
            std::cerr << "Failed to delete 33: " << e.what() << '\n';
        }
    
        l.Print();
    
        return 0;
    }