使用优先队列对链表进行排序

Posted

技术标签:

【中文标题】使用优先队列对链表进行排序【英文标题】:Sort linked list using priority queue 【发布时间】:2018-01-21 19:00:59 【问题描述】:
public class SortList
   class ListNode
      ListNode next;
      int val;

    public ListNode(int val)
      this.val = val;
     
   
public static ListNode sortList(ListNode head) 
    if(head == null)
        return null;
    PriorityQueue<ListNode> pq = new PriorityQueue<ListNode>( (a,b) -> (a.val - b.val));
    while(head != null)
        pq.add(head);
        head = head.next;
    
    ListNode pointer = pq.poll();
    ListNode result = pointer;
    while(pq.size() >0 )
    System.out.println(pq.size());
        ListNode nextTemp = pq.poll();
        pointer.next = nextTemp;
        pointer = pointer.next;
    
    return result;

  public static void main(String[] args) 
  ListNode head = new ListNode(3);
  ListNode n2 = new ListNode(2);
  ListNode n3 = new ListNode(5);
  ListNode n4 = new ListNode(9);
  ListNode n5 = new ListNode(7);
  ListNode n6 = new ListNode(4);
  head.next = n2;
  n2.next = n3;
  n3.next = n4;
  n4.next = n5;
  n5.next = n6;
  n6.next = null;
  ListNode result = sortList(head);
   while(result != null)
   System.out.println(result.val);
   result = result.next;
    
  
 

我想使用优先级队列对链表进行排序,但是为什么在 poll() 直到队列为空时会出现无限循环?列表大小减小但增加,优先级队列永远不会为空。

输出:

6
5
4
3
2
1
1
2
3
4
6
7
9
2
3
4
6
7
9
2
3
4
6
7
9
2
3
4
6
7
9
2
3
4
6

.......无限循环

【问题讨论】:

欢迎来到 ***。请阅读有关如何提问的帮助,尤其是有关提供Minimum Complete Verifiable Example 的部分。 @manchiu 你可以为我们发布整个代码吗?这对我来说很容易,因为我不必为 ListNode 和 main 方法编写代码。谢谢 能否也提供程序的错误或输出? 与您的直接问题无关,但您的比较中有一个严重的错误。见blog.mischel.com/2016/11/21/… pq.size() 的输出是否显示项目数量正在减少?它会变为 0 然后停留在那里,还是只是给你随机值?根据您显示的代码,您描述的行为似乎是不可能的。但是,您确实有一个错误:您添加到结果列表的最后一个节点将指向它在进入队列之前指向的任何内容。返回前需要设置pointer.next = null 【参考方案1】:

让我们看看你的输出:

6
5
4
3
2
1  Up to this point, you're removing items from the priority queue
1  This is the first item in the sorted list output
2
3
4
6
7
9  End of the sorted list output
2  ?? This happens because 9 is pointing to 2 in the original list.
3
4
6
7
9

从您的输出中可以清楚地看出,您运行的代码与您发布的代码不同。我知道这是因为输出不包含值“5”,并且您的输出中有 7 个不同的项目,但您的代码中只有 6 个。

您的无限循环不在优先级队列中。您可以通过修改 main() 来证明这一点,以便它在开始编写列表时输出一条消息,如下所示:

ListNode result = sortList(head);
System.out.println("Sorted list is:"); // start output
while(result != null)
    System.out.println(result.val);
    result = result.next;

正如我在 cmets 中指出的那样,问题在于优先级队列中的最后一项具有非空 next 指针。因此,当您将其删除并将其添加到结果列表中时,您最终会出现一个循环。结果列表最终如下所示:

1 -> 2 -> 3 -> 4 -> 6 -> 7 -> 9 ->
     ^                            \
      \                           /
       <-----<---------<--------<-

要解决此问题,请修改您的 sortList 方法,使其将列表中最后一项上的 next 指针设置为 null

while(pq.size() >0 )
    System.out.println(pq.size());
    ListNode nextTemp = pq.poll();
    pointer.next = nextTemp;
    pointer = pointer.next;


pointer.next = null;  // terminate the list!!
return result;

这种错误很容易用调试器诊断出来。您可以单步执行代码以查看确切它在做什么,并且您可以设置断点以便代码将在特定行停止执行。如果您一直在使用调试器,您可能会在几分钟内发现这个问题。如果您不知道如何使用它,请学习。现在。

诊断这些问题的另一种方法是放置输出语句,正如我所展示的。一个简单的System.out.println("Finished the sort."); 会告诉您排序实际上正在完成,并且问题稍后会发生。这是我们在拥有大量源代码级调试器之前使用的技术,今天它对于调试服务、网页和其他不方便在调试器中运行的程序仍然非常方便。

【讨论】:

谢谢 Jim,通过添加 pointer.next = null 修复了无限循环。

以上是关于使用优先队列对链表进行排序的主要内容,如果未能解决你的问题,请参考以下文章

优先级队列(从头开始)和链表

优先队列

优先队列

[LeetCode]23. 合并K个排序链表(优先队列;分治待做)

使用链表的优先队列

我有一个字符串,我需要根据自定义顺序进行排序,并且我正在使用优先级队列,但优先级队列因重复而失败 [重复]