[英]Correctly implementing a singly linked list C++
我有一个列出雇主名称的清单,例如:
节点1:Jill, Matt ,Joe,Bob, Matt
节点2:杰夫,詹姆斯, 约翰 ,乔纳森, 约翰 ,爱德华
节点3:Matt,Doe, Ron ,Pablo, Ron , Chase , Ron ,Chase,Loui
而且我正尝试将其到达重复出现的位置,并将其发送到列表的最前面并删除该当前节点,以使其看起来像这样
节点1: Matt ,Jill,Joe,Bob
节点2: John ,Jeff,James,Jonathan,Edward
节点3: Chase , Ron ,Matt,Doe,Pablo,Loui
不幸的是,我的输出接近我想要的。 它正在删除重复的条目,但没有发送到最前面。 。
我的输出:
节点1:Jill, Matt ,Joe,Bob,
好吧,走着瞧:
当您在此时点击if (ptr->data == p->data)
时:
pp
指向列表的末尾 p
是您的新节点(没有指向它,也没有指向任何东西) ptr
指向具有重复数据的节点 为了删除节点,您实际上需要使next
指针指向ptr
否则如何从列表中删除ptr
? 因此,您实际上需要检查:
if (head && head->data == p->data)
{
// do nothing as duplicate entry is already head of list
delete p;
return;
}
node *ptr = head;
while (ptr)
{
if (ptr->next && ptr->next->data == p->data)
{
node *duplicate = ptr->next;
ptr->next = duplicate->next; // skip the duplicate node
duplicate->next = head; // duplicate points to head
head = duplicate; // head is now the duplicate
delete p; // otherwise leaking memory
return;
}
ptr = ptr->next;
}
if (pp) // points to tail as per your code
{
pp->next = p;
++N;
}
我将变量名更改为更易读,但保留了前向声明,以防您需要这样的声明。 我发现的问题是,您始终将节点插入列表的末尾,无论您是否发现它是重复的。 此外,您的评论行似乎很近,但仅当单独出现时。 使用pp=p
东西,会引起问题。 请尝试以下操作,看看是否可行。 您仍然会泄漏内存,但是它将帮助您入门:
void list::put(int i) { //Where i is a random number
node *current =head;
node *added =new node(employers[i]);
node *tail =head;
node *prev = NULL;
bool foundRepeat = false;
while (current!=NULL)
{
if (current->data == added->data)
{
if (prev)
prev->next = current->next;
current->next=head;
head=current;
foundRepeat = true;
break;
}
prev = current;
current=current->next;
}
if (!foundRepeat)
{
while (tail->next)
{
tail=tail->next;
}
tail->next=added;
}
N++;
}
对于它的价值,我可能会这样实现。
class EmployerCollection
{
public:
typedef std::list<std::string> EmployerList;
public:
bool AddEmployer(const std::string& name)
{
EmployerList::const_iterator it = std::find(m_employers.begin(), m_employers.end(), name);
if (it != m_employers.end()) // Already exists in list.
{
m_employers.splice(m_employers.begin(), m_employers, it, std::next(it));
return true;
}
m_employers.push_front(name);
return false;
}
private:
EmployerList m_employers;
};
int main()
{
const int NUM_EMPLOYERS = 15;
std::string employers[NUM_EMPLOYERS] = {"Jill", "Jeff", "Doe", "Pablo", "Loui", "Ron", "Bob", "Joe", "Monica", "Luis", "Edward", "Matt", "James", "Edward", "John"};
EmployerCollection c;
for (int i=0; i<NUM_EMPLOYERS; i++)
{
bool duplicate = c.AddEmployer(employers[i]);
printf("Added %s to employer list - duplicate: %s \n", employers[i].c_str(), duplicate ? "True" : "False");
}
system("pause");
}
我添加了查找功能
typedef struct node{
string data;
struct node *net, *prev;
}node;
class list {
public:
list():head(NULL), N(0){}
~list(){
//Implementation for cleanup
}
void add(string name){ //rather than accessing the global data, use the value passed
node* p = new node(name);
p->next=p->prev=NULL;
node* pp = find(name);
if(pp==NULL){
// No match found, append to rear
if(head==NULL)
head=p; //list empty, add first element
else{
node* cur=head;
while(cur->next!=NULL) //Keep looking until a slot is found
cur=cur->next;
cur->next=p;
p->prev=cur;
}
}
else{
//Match found, detach it from its location
node* pPrev = pp->prev;
pPrev->next = pp->next;
pp->next->prev=pPrev;
p->next = head; //append it to the front & adjust pointers
head->prev=p;
}
N++;
}
//MER: finds a matching element and returns the node otherwise returns NULL
node* find(string name){
node *cur=head;
if(cur==NULL) // is it a blank list?
return NULL;
else if(cur->data==head) //is first element the same?
return head;
else // Keep looking until the list ends
while(cur->next!=NULL){
if(cur->data==name)
return cur;
cur=cur->next;
}
return NULL;
}
friend ostream& operator << (ostream& os, const list& mylist);
private:
int N;
node *head;
};
现在有些人可能会告诉您使用STL中的列表n永远不要编写您自己的代码,因为您无法击败STL,但是对我来说,很好的是,您正在实现自己的代码,以清楚地了解它在现实中的工作方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.