问题
I have a header file called StringList.h that includes the following:
#include <string>
using namespace std;
class StringList;
class StringListNode
{
friend class StringList;
private:
StringListNode * pPrev;
string data;
StringListNode * pNext;
};
class StringList
{
public:
StringList();
~StringList();
void addToBottom(string s);
void addToTop(string s);
void remove(string s);
string print();
void clear();
bool isEmpty() {return (pTop==NULL);}
private:
StringListNode * pTop;
StringListNode * pBottom;
};
My StringList.cpp file will have the definitions to all my functions. So far I figured out how to addtotop and addtoBottom works
addToTop:
if(isEmpty())
{
StringListNode * pNewNode;
pNewNode = new StringListNode;
(*pNewNode).data = s;
pTop=pNewNode;
pBottom=pNewNode;
(*pNewNode).pPrev = NULL;
(*pNewNode).pNext = NULL;
}
else //it's not empty
{
StringListNode * pNewNode;
pNewNode = new StringListNode;
(*pNewNode).data = s;
(*pNewNode).pNext = pTop;
(*pTop).pPrev = pNewNode;
(*pNewNode).pPrev =NULL;
pTop=pNewNode;
}
addToBottom is basically the same but replacing pTop with pBottom in the else statement. Now, where im stuck is at remove. I want to go through each nod until it finds the string within *data and delete it. However i dont really know how to make the previous pointer to the node i want deleted point to the pNext of the next node. Any suggestions?
print():
string StringList::print()
{
string result;
StringListNode * pCurrent;
pCurrent=pTop;
while(pCurrent!=NULL)
{
result+=(*pCurrent).data+"\n";
pCurrent=(*pCurrent).pNext;
}
return result;
}
回答1:
Assuming you have three nodes in a doubly-linked list and you want to delete the middle node, identified by curr:
curr ----------------------+
|
v
+--------+ +--------+ +--------+
...----| pPrev |<------| pPrev |<------| pPrev |<---...
| Node 1 | | Node 2 | | Node 3 |
...--->| pNext |------>| pNext |------>| pNext |----...
+--------+ +--------+ +--------+
The two relinking operations are:
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
You can now dispose of curr in any suitable way. The only trick is dealing with end-cases; what happens when you delete the node at the start or end of the list, or the only node in the list. What's appropriate depends on how you've created your list. Do you have null pointers, or a circular list, or ...
Given that you use null pointers to mark the ends of the list, you have to check for null pointers when deleting.
if (curr->pPrev != 0)
curr->pPrev->pNext = curr->pNext;
if (curr->pNext != 0)
curr->pNext->pPrev = curr->pPrev;
You also have to deal with curr being the head of the list, adjusting the head (pTop) or with it being the tail of the list, adjusting the tail (pBottom). You also have to deal with curr being the only node in the list.
Superficially working code...not validated with valgrind. However, the repeated use of the toString() member function (née print()) suggests that the list structure is OK. No promises about no leaks.
#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;
}
来源:https://stackoverflow.com/questions/17635481/remove-function-in-a-linked-list