【问题标题】:Merging 2 linked lists and appending to the end of linked lists c++合并2个链表并附加到链表c ++的末尾
【发布时间】:2015-08-11 22:37:01
【问题描述】:

到目前为止,我没有太多东西,但我正在尝试掌握使用链表的窍门。

结构:

struct Node 
{
   int value;
   Node *next;
};

如何将节点添加到列表末尾?我只是想接收一个指向列表头部的指针和一个 int 值作为新节点添加。当我尝试运行我目前拥有的东西时,我得到了一个例外。

void addNode(Node* head, int x) 
{

    Node* temp = new Node;
    temp->data = x;
    temp->next = NULL;

     if(!head) 
     { 
         head = temp;
         return;
     } 
     else 
     {
         Node* last = head;
         while(last->next) 
         last=last->next;

         last->next = temp;
     }
}

我还没有真正开始着手合并这两个列表。我只知道我需要获取 2 个链表(或指向 2 个链表头部的指针?),然后遍历所有节点的列表。

E.G:链表 1 有 3 个节点:4、10、20。 链表 2 有 4 个节点:2、5、15、60。

合并列表函数将生成一个以 2,4,5,10,15,20,60 作为节点的新链表。

编辑:在我的 main 中,我正在调用 addNode 函数,如下所示:

Node *head = new Node;

insertAtEnd(head,20);

这是正确的还是可能是异常的原因?

【问题讨论】:

  • 我首先通过引用传递头指针。 Node *& head。否则你只是将指针值传递给这个函数,head = ... 对调用者没有任何意义。
  • 这里有一些一般性的提示(当然在你的课程材料中已经提到过): 1) 将节点添加到单链表的后面比将它添加到前面要慢得多。 2)您可以通过维护一个指向最后一个节点的迭代器(一个指针就足够了)来避免这种缓慢。这也避免了在合并时遍历任一列表。
  • @Bobo Amitheson 您如何合并列表?您是否必须使用新节点创建新的第三个列表,还是需要将所有节点从第二个列表移动到第一个列表?
  • 我的目标是创建一个包含新节点的第三个列表。
  • @BoboAmitheson 在这种情况下,您无法避免像我建议的那样遍历列表,因为假设您正在修改列表。

标签: c++ linked-list


【解决方案1】:

按如下方式声明函数

void addNode( Node* &head, int x) ;

而不是这个代码sn-p

Node *head = new Node;

insertAtEnd(head,20);

你必须通过以下方式第一次调用该函数

Node *head = nullptr; // or NULL

addNode(head,20);

请注意,您的帖子中没有名称为 insertAtEnd 的函数。有函数addNode.:)

如果您需要合并两个列表,那么您可以使用这个演示程序作为示例。当然,您需要添加一些其他功能,例如删除列表以获得完整的项目。

#include <iostream>

struct Node 
{
    int value;
    Node *next;
};

Node * insert( Node *current, int value )
{
    Node *tmp;

    if ( current == nullptr )
    {
        tmp = new Node { value, nullptr };
    }
    else
    {
        tmp = new Node { value, current->next };
        current->next = tmp;
    }

    return tmp;
}

std::ostream & display( Node *head, 
                        std::ostream &os = std::cout,
                        const char *delimiter = " " )
{
    for ( ; head; head = head->next ) os << head->value << delimiter;

    return os;
}

Node * merge( Node * &head1, Node * &head2 )
{
    Node *new_head = nullptr;
    Node *current  = nullptr; 

    while ( head1 != nullptr && head2 != nullptr )
    {
        Node *tmp;
        if ( head2->value < head1->value )
        {
            tmp = head2;
            head2 = head2->next;
        }
        else
        {
            tmp = head1;
            head1 = head1->next;
        }

        tmp->next = nullptr;
        if ( new_head == nullptr )
        {
            new_head = tmp;
            current = new_head;
        }
        else
        {
            current->next = tmp;
            current = current->next;
        }
    }

    if ( head1 != nullptr ) new_head == nullptr ? new_head : current->next = head1;
    if ( head2 != nullptr ) new_head == nullptr ? new_head : current->next = head2;


    head2 = nullptr;
    head1 = new_head;

    return new_head;
}

int main() 
{
    Node *list1 = nullptr;
    Node *list2 = nullptr;

    list1 = insert( list1, 4 );
    insert( insert( list1, 10 ), 20 );

    display( list1, std::cout << "List1: " ) << std::endl;

    list2 = insert( list2, 2 );
    insert( insert( insert( list2, 5 ), 15 ), 60 );

    display( list2, std::cout << "List2: " ) << std::endl;

    std::cout << std::endl;

    merge( list1, list2 );

    display( list1, std::cout << "List1: " ) << std::endl;
    display( list2, std::cout << "List2: " ) << std::endl;

    return 0;
}

程序输出是

List1: 4 10 20 
List2: 2 5 15 60 

List1: 2 4 5 10 15 20 60 
List2: 

【讨论】:

    【解决方案2】:

    通过这样做:

    void addNode(Node* head, int x) 
    // here ---------^
    

    然后是这个:

     head = temp; // here
    

    您只是修改了本地的head 指针,它采用了从调用者传递的地址值。由于head 不是对指针的实际引用(它只是一个指针),因此结果是调用者的指针以head 的形式传递,保持不变。您永远不会将分配的节点附加到列表中,泄漏内存,这将成为悲伤的一天...

    改为通过引用传递指针。修复它,然后修复无效的 data 成员,它实际上应该是 value 和一个用于遍历列表以找到结尾的指针,结果可能如下所示:

    #include <iostream>
    
    struct Node
    {
        int value;
        Node *next;
    };
    
    void addNode(Node*& head, int x)
    {
        Node **pp = &head;
        while (*pp)
            pp = &(*pp)->next;
        *pp = new Node;
        (*pp)->value = x;
        (*pp)->next = nullptr;
    }
    
    void printList(const Node *head)
    {
        for (; head; head = head->next)
            std::cout << head->value << ' ';
        std::cout << '\n';
    }
    
    void freeList(Node *&head)
    {
        while (head)
        {
            Node *p = head;
            head = p->next;
            delete p;
        }
    }
    
    int main()
    {
        Node *head = nullptr;
    
        for (int i=1; i<=5; ++i)
            addNode(head, i);
    
        printList(head);
        freeList(head);
    }
    

    输出

    1 2 3 4 5 
    

    我将实现实际合并的任务留给您,但这应该足以让您建立并运行一个可管理的列表。


    更新:来自 OP 的编辑问题:

    Node *head = new Node;
    
    insertAtEnd(head,20);
    

    除了现在是一个完全不同的命名函数之外,您的节点是默认初始化的。在您的情况下,这意味着来自new Node; 的结果Node 具有两个 valuenextindeterminate 值。然后您将其传递给您的函数,该函数假定一个确定的值(null)来终止您的循环。

    这可以通过多种方式解决;上面代码的机制就是这样一种方式。如果列表管理代码理解NULL表示无列表,则无需预先分配头节点。您的addNode 原始帖子似乎至少尝试遵循该口头禅。

    【讨论】:

      【解决方案3】:

      编辑:在我的 main 中,我这样调用 addNode 函数:

      Node *head = new Node;
      insertAtEnd(head,20);
      

      这是错误的。您没有初始化head-&gt;next,因此在insertAtEnd 内代码while(last-&gt;next) last=last-&gt;next; 将尝试比较未初始化的指针,如果它不为空,将取消引用它。这可能会使您的程序崩溃而不是抛出异常。再说一次,这是未定义的行为,所以任何事情都可能发生。

      由于您的插入函数已经涵盖了插入空列表的情况,我会简单地调用

      head = nullptr;
      insertAtEnd(head,20)`;
      

      除此之外,还有永远不会在函数外更新head 指针的错误,其他答案已经涵盖了这一点。

      【讨论】:

        【解决方案4】:

        这可能是异常的原因:

        struct Node 
        {
           int value;     <-----  Node structure has value property
           Node *next;
        };
        
        
        Node* temp = new Node;
        temp->data = x;   <------ Assigning to data property of Node which does not exists
        temp->next = NULL;
        

        要添加列表,您可以使用相同的方法

        void addNode(Node* head, Node* head2) 
        {
        
          Node* last = head;
          while(last->next) last=last->next;
        
          last->next = head2;
        }
        

        【讨论】:

        • 这应该会导致编译器错误,而不是异常。
        • @skazska 你为什么要告诉我们 skazski?:)
        • @skazska 您写道,“这可能是异常的原因”,这是不正确的。这将是编译错误的原因。只是指出这一点。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-13
        • 2012-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多