当前位置: 首页 > 知识库问答 >
问题:

合并两个已排序的列表时出错

曾涵育
2023-03-14

以下是我在Leetcode上解决“合并两个排序列表”算法问题的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *dummy, *pre;
        dummy->next = l1;
        pre = dummy;
        while(l1 != NULL & l2 != NULL) {
            if(l1->val < l2->val) {
                pre = l1;
                l1 = l1->next;
            } else {
                pre->next = l2;
                l2->next = l1;
                pre = l2;
                l2 = l2->next;
            }
        }
        if(l2 != NULL) {
            pre->next = l2;
        }
        return dummy->next;

    }
};

我得到了一个运行时错误。但是我的代码有什么问题?

共有3个答案

韦智刚
2023-03-14

代码中的主要问题是您正在使用:

    dummy->next = l1;

虚拟尚未初始化为指向有效对象时。

您还使用了按位

    while(l1 != NULL & l2 != NULL) {

这里有一个建议的实现。

PS它没有经过测试,但在我看来是正确的。

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {

   ListNode* ret = NULL;
   ListNode* pre = NULL;

   // Make sure the start of the list to be returned points to the right
   // ListNode.
   if ( l1 != NULL && l2 != NULL )
   {
      if ( l1->val < l2->val )
      {
         ret = l1;
         l1 = l1->next;
      }
      else
      {
         ret = l2;
         l2 = l2->next;
      }
   }
   else if ( l1 != NULL )
   {
      return l1;
   }
   else
   {
      return l2;
   }

   pre = ret;

   while(l1 != NULL && l2 != NULL) {

      // Figure out where pre->next must point to.
      // Advance l1 and l2 appropriately.
      if(l1->val < l2->val) {
         pre->next = l1;
         pre = l1;
         l1 = l1->next;
      } else {
         pre->next = l2;
         pre = l2;
         l2 = l2->next;
      }
   }

   // Make sure pre->next points to the remaining ListNodes.
   // They could be in l1 or l2.
   if ( l1 != NULL )
   {
      pre->next = l1;
   }

   if( l2 != NULL)
   {
      pre->next = l2;
   }

   return ret;
}

郎同化
2023-03-14

我认为您得到了分段错误(核心转储),因为您试图访问无效的内存:

dummy->next = l1;

在访问它们的成员之前,您应该将内存分配给*虚拟*前

也可以使用

while(l1 != NULL & l2 != NULL) {

while(l1 != NULL && l2 != NULL) {

使用new操作符分配内存,请使用delete释放内存并避免内存泄漏。

还要注意,实现本身在逻辑上是错误的。请参阅此处以了解更好的实现。

下面是一个简单的递归实现:

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 
{
  ListNode* result = NULL;

  /* Base cases */
  if (l1 == NULL) 
     return (l2);
  else if (l2 == NULL) 
     return (l1);

  if (l1->data <= l2->data) 
  {
     result = l1;
     result->next = mergeTwoLists(l1->next, l2);
  }
  else
  {
     result = l2;
     result->next = mergeTwoLists(l1, l2->next);
  }
  return(result);
}

华章横
2023-03-14

我相信一个正确的实现将需要比OP中更多的代码。我假设输入列表l1l2按降序排序(即从头部到尾部从最大到最小)。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *pnt1 = l1;
        ListNode *pnt2 = l2;
        ListNode *head;

        // assign the head pointer to larger head of the two input lists
        if (l1->val > l2->val) {
            head = l1;
        }
        else {
            head = l2;
        }

        // walk through both lists sequentially,
        // and splice together the sorted list
        while (pnt1->next != NULL & pnt2->next != NULL) {
            if(pnt2->val > pnt1->next->val && pnt1->val > pnt2->val) {
                ListNode* next = pnt1->next;
                pnt1->next = pnt2;
                pnt1 = next;
            }
            else if(pnt2->val > pnt1->next->val && pnt1->val <= pnt2->val) {
                ListNode* next = pnt2->next;
                pnt2->next = pnt1;
                pnt2 = next;
            }
            else if(pnt2->val <= pnt1->next->val && pnt1->val > pnt2->val) {
                pnt1 = pnt1->next;
            }
        }

        // handle edge case where end of one or two list(s) has been reached
        if (pnt1->next == NULL && pnt2->next == NULL) {
            if (pnt1->val > pnt2->val) {
                pnt1->next = pnt2;
            }
            else {
                pnt2->next = pnt1;
            }
        }
        else if (pnt1->next == NULL) {
            while (pnt2->next != NULL) {
                if (pnt1->val > pnt2->next->val) {
                    ListNode* next = pnt2->next;
                    pnt2->next = pnt1;
                    pnt1->next = next;
                    break;
                }
                pnt2 = pnt2->next;
            }
            if (pnt2->next == NULL) {
                pnt2->next = pnt1;
            }
        }
        else if (pnt2->next == NULL) {
            while (pnt1->next != NULL) {
                if (pnt2->val > pnt1->next->val) {
                    ListNode* next = pnt1->next;
                    pnt1->next = pnt2;
                    pnt2->next = next;
                    break;
                }
                pnt1 = pnt1->next;
            }
            if (pnt1->next == NULL) {
                pnt1->next = pnt2;
            }
        }

        return head;
    }
};
 类似资料:
  • 假设列表“A”是1- 请回顾一下这个,帮我即兴创作

  • NowCoder 题目描述 解题思路 递归 // java public ListNode Merge(ListNode list1, ListNode list2) { if (list1 == null) return list2; if (list2 == null) return list1; if (list1.val <= lis

  • 问题内容: 在我的作业中,第三步是调用方法merge来合并list1中的两个列表,以便list1 保持排序。 我编写了代码,但效果不佳,输出显示错误,因为排序很重要 问题答案: 假设两个列表都已排序,则只需要一个循环: 如果未排序,则需要两个循环:

  • 我正试图想出一个分而治之的算法来合并j个排序列表和n个元素,但我被卡住了;我不知道如何把这个问题分成更小的子问题。我希望合并算法更高效,如下所示: 合并前两个列表;然后将结果列表与第三个列表合并;然后将结果列表与第四个列表合并,以此类推,该列表取O(j*jn)。

  • 一、题目 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。 二、解题思路 Step1.定义一个指向新链表的指针,暂且让它指向NULL; Step2.比较两个链表的头结点,让较小的头结点作为新链表的头结点; Step3.有两种方法。 ①递归比较两个链表的其余节点,让较小的节点作为上一个新节点的后一个节点; ②循环比较两个链表的其余节点,让较小的节点作为上一个新节点的后一

  • 有人告诉我,在线性时间内,将两个已经排序的大小不同的数组A和B合并成一个数组C。 通过线性时间,我明白了这个算法的时间复杂度必须是O(n)。后来,我还被告知在合并数组时执行排序。 我的一个想法是创建一个算法,在两个数组中都有两个指针,指向最小的元素。指向的最小元素将进入新数组。当一个数组耗尽时,另一个数组的剩余元素将复制到新数组中。 由于几个月前我刚开始编程,我发现这很难实现,因此我决定执行合并排