关于链表的排序(Java)

本文介绍了一种在O(nlogn)时间内使用常数级空间复杂度对链表进行排序的方法,通过类似快速排序的策略,将链表分为小于、等于和大于分割点的三部分,并递归地对小于和大于的部分进行排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


代码:java

题目描述

在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。
Sort a linked list in O(n log n) time using constant space complexity.

节点定义

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */

思路

类似快排,根据第一个节点从前往后扫
小于放入一个链表,大于放入一个链表,等于放入一个链表
然后对于小于和大于的链表递归调用
最后把三个组合在一起,返回小于的链表

注意的点(摔过的坑 ):

  1. 小于的链表要判定是否为空,由于大于的链表放在后面,null不影响链接
  2. 命名十分接近,要小心是head还是尾巴,这玩意整死我了
  3. 切割的时候,返回节点node1要把next删掉,不然会有很长的一条冗余数据
  4. 留个无效的头节点是很好的,可以避免空链表null产生的很多麻烦,但是要记得删

代码

public class Solution {
    ListNode cut(ListNode node0){//切割出node0后面一个节点node1,返回切掉的节点
        ListNode node1=node0.next;
        node0.next=node1.next;
        node1.next=null;
        return node1;
    }
    
    boolean add(ListNode nodetail,ListNode addnode){//只会加不会后移
        if(nodetail.next!=null)return false;
        nodetail.next=addnode;
        return true;
    }
    
    public ListNode sortList(ListNode head) {
        if(head==null)return head;
        if(head.next==null)return head;//空节点和单个节点都直接返回
        ListNode tempNode=head;
        //ListNode tempNodeNext=head.next;
        //头节点,用0占掉,返回的时候记得删
        ListNode lessNodeHead=new ListNode(0);
        ListNode equalNodeHead=new ListNode(0);
        ListNode greaterNodeHead=new ListNode(0);
        //当前节点
        ListNode lessNode=lessNodeHead;
        ListNode equalNode=equalNodeHead;
        ListNode greaterNode=greaterNodeHead;
        
        int div=tempNode.val;//分割点
        if(add(equalNode,new ListNode(div))){
            equalNode=equalNode.next;
        }
        while(tempNode.next!=null){
           // tempNodeNext=tempNode.next;
            if(tempNode.next.val==div){
                if(add(equalNode,cut(tempNode))){
                    equalNode=equalNode.next;
                }
                continue;
            }
            if(tempNode.next.val<div){
                if(add(lessNode,cut(tempNode))){
                    lessNode=lessNode.next;
                }
                continue;
            }
            if(tempNode.next.val>div){
                if(add(greaterNode,cut(tempNode))){
                    greaterNode=greaterNode.next;
                }
                continue;
            }
        }

        //记得去头
        if(lessNodeHead.next==null)lessNodeHead=lessNodeHead.next;
        else lessNodeHead=sortList(lessNodeHead.next);    
        if(greaterNodeHead.next==null)greaterNodeHead=greaterNodeHead.next;
        else greaterNodeHead=sortList(greaterNodeHead.next);
        equalNodeHead=equalNodeHead.next;
        
        //找尾巴
        lessNode=lessNodeHead;
        equalNode=equalNodeHead;
        greaterNode=greaterNodeHead;
        if(lessNode!=null)while(lessNode.next!=null)lessNode=lessNode.next;
        if(equalNode!=null)while(equalNode.next!=null)equalNode=equalNode.next;
        //组合
        equalNode.next=greaterNodeHead;
        if(lessNode!=null)lessNode.next=equalNodeHead;
        else lessNodeHead=equalNodeHead;
         return lessNodeHead;
    
    }
}

想不到怎么优化,而且貌似空间复杂度不是常数···

### Java 链表排序方法 #### 归并排序应用于双向链表 对于Java中的双向链表,一种高效的排序方式是采用归并排序算法。此算法通过递归的方式不断分割列表直到每个子列表仅含单个节点或为空,之后再逐步合并这些有序的小片段形成最终完全排序的大列表[^2]。 具体操作流程如下: - 使用快慢指针法来定位中间位置从而划分成两半; - 对每半个继续执行相同逻辑直至不能再分; - 将各段按升序重新组合起来; 以下是基于上述原理编写的`DoublyLinkedList`类的部分源码展示用于说明如何实现这一功能[^1]: ```java public class DoublyLinkedList { private Node head; // ...其他成员变量和辅助函数... /** Sorts the linked list using merge sort algorithm */ public void sort() { if (head == null || head.next == null) return; // Already sorted or empty head = divide(head); } /** Divides and sorts recursively, then merges two halves of the list */ private Node divide(Node node){ if(node==null||node.next==null)return node; Node mid=findMid(node); // Find midpoint with slow/fast pointers technique. Node secondHalfStart=mid.next; mid.next=null;// Split into two lists. Node leftSorted=divide(node); // Recursively apply on both parts. Node rightSorted=divide(secondHalfStart); return merge(leftSorted,rightSorted);// Merge them back together after sorting. } } ``` 为了完成整个程序还需要编写`findMid()`以及`merge()`这两个帮助性的私有方法,在这里省略了具体的细节以便聚焦于核心概念之上。 另外值得注意的是,除了归并排序之外还有其他的排序策略适用于不同场景下的需求,比如插入排序就非常适合处理几乎已经是顺序排列的数据集[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值