假设您在双向链表中有三个节点,并且您要删除中间节点,由 标识curr
:
curr ----------------------+
|
v
+--------+ +--------+ +--------+
...----| pPrev |<------| pPrev |<------| pPrev |<---...
| Node 1 | | Node 2 | | Node 3 |
...--->| pNext |------>| pNext |------>| pNext |----...
+--------+ +--------+ +--------+
两个重新链接操作是:
curr->pPrev->pNext = curr->pNext; // Previous node's next points to curr's next
curr->pNext->pPrev = curr->pPrev; // Next node's previous points to curr's previous
您现在可以curr
以任何合适的方式进行处理。唯一的技巧是处理最终情况;当您删除列表开头或结尾的节点或列表中的唯一节点时会发生什么。什么是合适的取决于您创建列表的方式。你有空指针,或者循环列表,或者......
鉴于您使用空指针来标记列表的结尾,因此您必须在删除时检查空指针。
if (curr->pPrev != 0)
curr->pPrev->pNext = curr->pNext;
if (curr->pNext != 0)
curr->pNext->pPrev = curr->pPrev;
您还必须处理curr
成为列表的头部,调整头部(pTop
)或作为列表的尾部,调整尾部(pBottom
)。您还必须处理curr
成为列表中唯一的节点。
表面上工作的代码...未使用valgrind
. 但是,重复使用toString()
成员函数 (née print()
) 表明列表结构是可以的。没有关于不泄漏的承诺。
#include <string>
using namespace std;
class StringList
{
private:
struct StringListNode
{
StringListNode *pPrev;
string data;
StringListNode *pNext;
};
public:
StringList() : pTop(0), pBottom(0) {}
~StringList();
void addToTop(const string &s);
void remove(const string &s);
string toString();
bool isEmpty() { return (pTop == NULL); }
private:
StringListNode *pTop;
StringListNode *pBottom;
StringListNode *find(const string &s);
};
string StringList::toString()
{
string result;
StringListNode *pCurrent = pTop;
while (pCurrent != NULL)
{
result += pCurrent->data + "\n";
pCurrent = pCurrent->pNext;
}
return result;
}
StringList::StringListNode *StringList::find(const string &s)
{
StringListNode *sp = pTop;
while (sp != 0 && sp->data != s)
sp = sp->pNext;
return sp;
}
void StringList::addToTop(const string &s)
{
if (isEmpty())
{
StringListNode * pNewNode = new StringListNode;
pNewNode->data = s;
pNewNode->pPrev = NULL;
pNewNode->pNext = NULL;
pTop = pNewNode;
pBottom = pNewNode;
}
else
{
StringListNode * pNewNode;
pNewNode = new StringListNode;
pNewNode->data = s;
pNewNode->pNext = pTop;
pNewNode->pPrev = NULL;
pTop->pPrev = pNewNode;
pTop = pNewNode;
}
}
void StringList::remove(const string &s)
{
StringListNode *curr = this->find(s);
if (curr == 0)
return;
if (curr->pPrev != 0)
curr->pPrev->pNext = curr->pNext;
if (curr->pNext != 0)
curr->pNext->pPrev = curr->pPrev;
if (pTop == curr)
pTop = curr->pNext;
if (pBottom == curr)
pBottom = curr->pPrev;
}
StringList::~StringList()
{
StringListNode *next;
for (StringListNode *sp = pTop; sp != 0; sp = next)
{
next = sp->pNext;
delete sp;
}
}
#include <iostream>
int main()
{
StringList s;
s.addToTop("abc");
std::cout << "After add abc: " << s.toString();
s.addToTop("def");
std::cout << "After add def: " << s.toString();
s.addToTop("ghi");
std::cout << "After add ghi: " << s.toString();
s.addToTop("jkl");
std::cout << "After add jkl: " << s.toString();
s.remove("def");
std::cout << "After del def: " << s.toString();
s.remove("ghi");
std::cout << "After del ghi: " << s.toString();
s.remove("abc");
std::cout << "After del abc: " << s.toString();
s.remove("jkl");
std::cout << "After del jkl: " << s.toString();
return 0;
}