C++ 正确实现单链表C++;

C++ 正确实现单链表C++;,c++,linked-list,C++,Linked List,我有一份雇主名单,包括: 节点1:Jill,Matt,Joe,Bob,Matt 节点2:杰夫、詹姆斯、约翰、乔纳森、约翰、爱德华 节点3:Matt,Doe,罗恩,Pablo,罗恩,蔡斯,罗恩,蔡斯,路易 我试着把它放到一个地方,如果它看到一个重复,它会把它发送到列表的前面,并删除当前的节点,这样它就会像这样 节点1:马特、吉尔、乔、鲍勃 节点2:约翰,杰夫,詹姆斯,乔纳森,爱德华 节点3:蔡斯,罗恩,马特,多伊,巴勃罗,路易 不幸的是,我的输出接近我想要的。它正在删除重复条目,但不会发送到前端

我有一份雇主名单,包括:

节点1:Jill,Matt,Joe,Bob,Matt

节点2:杰夫、詹姆斯、约翰、乔纳森、约翰、爱德华

节点3:Matt,Doe,罗恩,Pablo,罗恩蔡斯罗恩,蔡斯,路易

我试着把它放到一个地方,如果它看到一个重复,它会把它发送到列表的前面,并删除当前的节点,这样它就会像这样

节点1:马特、吉尔、乔、鲍勃

节点2:约翰,杰夫,詹姆斯,乔纳森,爱德华

节点3:蔡斯罗恩,马特,多伊,巴勃罗,路易

不幸的是,我的输出接近我想要的。它正在删除重复条目,但不会发送到前端

我的输出:


节点1:Jill,Matt,Joe,Bob,

我更改了变量名,使其更具可读性,但保留了转发声明,以防您需要这样做。我发现的问题是,您总是在列表末尾插入节点,而不管您是否发现它是重复的。此外,您的注释行看起来很接近,但只有在单独出现时。对于
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++;
}
好吧,让我们看看:

当您点击
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;
}

无论如何,我可能会这样实现它

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");
} 
class EmployeerCollection
{
公众:
typedef std::列出员工列表;
公众:
布尔加法器(常量标准::字符串和名称)
{
EmployerList::const_迭代器it=std::find(m_employers.begin(),m_employers.end(),name);
if(it!=m_employers.end())//已存在于列表中。
{
拼接(m_employers.begin(),m_employers,it,std::next(it));
返回true;
}
m_雇主。推_前线(姓名);
返回false;
}
私人:
雇主主义m_雇主;
};
int main()
{
const int NUM_雇主=15;
字符串雇主[NUM_雇主]={“吉尔”、“杰夫”、“多伊”、“巴勃罗”、“路易”、“罗恩”、“鲍勃”、“乔”、“莫妮卡”、“路易斯”、“爱德华”、“马特”、“詹姆斯”、“爱德华”、“约翰”};
雇主集合c;

对于(inti=0;i我添加了一个find函数

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;

};
typedef结构节点{
字符串数据;
结构节点*net,*prev;
}节点;
班级名单{
公众:
list():head(NULL),N(0){
~list(){
//清理的实现
}
void add(string name){//使用传递的值,而不是访问全局数据
节点*p=新节点(名称);
p->next=p->prev=NULL;
节点*pp=find(名称);
if(pp==NULL){
//未找到匹配项,请附加到后面
if(head==NULL)
head=p;//列表为空,添加第一个元素
否则{
节点*cur=头部;
while(cur->next!=NULL)//继续查找,直到找到插槽
cur=cur->next;
cur->next=p;
p->prev=cur;
}
}
否则{
//找到匹配项,将其从其位置分离
节点*pPrev=pp->prev;
pPrev->next=pp->next;
pp->next->prev=pPrev;
p->next=head;//将其附加到前面并调整指针
头->上一个=p;
}
N++;
}
//MER:查找匹配的元素并返回节点,否则返回NULL
节点*查找(字符串名称){
节点*cur=头部;
if(cur==NULL)//是否为空列表?
返回NULL;
否则如果(cur->data==head)//第一个元素是否相同?
回流头;
else//继续查找,直到列表结束
while(cur->next!=NULL){
如果(当前->数据==名称)
返回电流;
cur=cur->next;
}
返回NULL;
}

friend ostream&operator链表的正确实现方法是
std::list
有人知道插入列表前面的正确方法吗?@Mdjon26-您是否参加了相同的课程?添加到列表前面比添加到末尾容易得多。如果您不需要添加末尾,请尝试添加到前面。使用
A->B->C
现在添加
B
。你将得到一个从
A
B
的圆圈,回到
A
并丢失了
C
。更不用说内存泄漏了。是的,我不关心内存泄漏。他应该一边处理/一边学习它,尽管我可能应该提到它。你是循环正确,已更新并已修复…最好不要使用常量定义数组的大小
NUM_EMPLOYERS
。最好让编译器计算它。然后可以得到
NUM_EMPLOYERS
。首选:
std::string EMPLOYERS[]={STUFF};
然后
const int NUM_EMPLOYERS=sizeof(EMPLOYERS)/sizeof(employers[0]);
我真的看不出有什么区别,它纯粹是为了示例而使用的,并且在循环过程中使用了一个变量。首先,这里有一个手写字符串数组的事实违背了整个练习的目的。