You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LeetCode 148题Sort List冒泡排序栈溢出问题排查

问题分析:冒泡排序实现LeetCode 148时的栈溢出问题

问题背景

使用递归版冒泡排序解决LeetCode 148. Sort List问题,本地Eclipse运行小规模测试用例正常,但提交到LeetCode平台时触发栈溢出错误。原代码如下:

class Solution {
    public ListNode sortList(ListNode head) {
        return bubbleSort(head,size(head)-1,0);
    }

    int size(ListNode head){
        int c=0;
        while(head!=null){
            c++;
            head=head.next;
        }
        return c;
    }

    ListNode point(ListNode head,int index){
        for(int i=0;i<index;i++){
            head=head.next;
        }
        return head;
    }

    public ListNode bubbleSort(ListNode head,int r,int c){
        if(r==0){
            return head;
        }
        if(c<r){
            ListNode first = point(head,c);
            ListNode second = point(head,c+1);
            if(first.val > second.val){
                if(first==head){
                    first.next=second.next;
                    second.next=first;
                    head=second;
                }else{
                    ListNode prev=point(head,c-1);
                    prev.next=second;
                    first.next=second.next;
                    second.next=first;
                }
            }
            return bubbleSort(head,r,c+1);
        }else{
            return bubbleSort(head,r-1,0);
        }
    }
}

栈溢出原因

  • 递归深度超出JVM栈上限:冒泡排序的递归次数等于链表长度n。LeetCode的测试用例包含长度上万的链表,而Java默认栈深度通常在1000左右,当n远大于这个值时,递归调用栈会被撑爆,触发StackOverflowError。
  • 本地测试规模有限:本地运行的链表长度较短,递归深度未超过栈上限,因此未出现错误。

修复方法

将递归版冒泡排序改为迭代版,彻底规避递归栈溢出问题,同时优化原代码中反复遍历链表的低效操作。

迭代版冒泡排序实现

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        
        int size = size(head);
        // 外层循环控制排序轮数,每轮将最大元素移至未排序部分末尾
        for (int i = size - 1; i > 0; i--) {
            ListNode prev = null;
            ListNode curr = head;
            boolean swapped = false;
            // 内层循环遍历未排序区间,比较并交换相邻节点
            for (int j = 0; j < i; j++) {
                ListNode nextNode = curr.next;
                if (curr.val > nextNode.val) {
                    swapped = true;
                    // 处理交换逻辑
                    if (prev == null) {
                        // 交换头节点
                        curr.next = nextNode.next;
                        nextNode.next = curr;
                        head = nextNode;
                        prev = nextNode;
                    } else {
                        prev.next = nextNode;
                        curr.next = nextNode.next;
                        nextNode.next = curr;
                        prev = nextNode;
                    }
                } else {
                    prev = curr;
                    curr = nextNode;
                }
            }
            // 某轮无交换,说明链表已完全有序,提前终止
            if (!swapped) {
                break;
            }
        }
        return head;
    }

    private int size(ListNode head) {
        int count = 0;
        while (head != null) {
            count++;
            head = head.next;
        }
        return count;
    }
}

优化说明

  • 加入swapped标志:若某一轮遍历未发生交换,直接终止排序,减少无效遍历。
  • 避免重复遍历:迭代版在单次遍历中完成相邻节点的比较与交换,无需像原递归版那样反复调用point方法从头查找节点,提升了执行效率。

内容的提问来源于stack exchange,提问作者Shoaib Alam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:37:16