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

如何在单链表上实现希尔排序?寻求技术帮助

单链表版希尔排序实现指南

首先得给你点个赞,敢从熟悉的数组版希尔排序拓展到链表版,这个探索思路超棒!不过链表和数组的核心差异在于无法随机访问,你的现有代码刚好踩了这个坑,咱们一步步梳理问题,再给出可行的实现方案。

你当前代码的核心问题

  1. moveptr函数传值调用无效:C语言是传值调用,你在moveptr里修改的ptr只是函数内部的副本,外部的b根本不会跟着移动。比如调用moveptr(b,j)后,b还是指向head,直接导致后续的比较逻辑完全错误。
  2. a指针越界访问:shellsort里a初始指向head,每次i循环都执行a=a->next,当i达到size时,a会变成NULL,再访问a->data就会触发空指针崩溃。
  3. 分组逻辑不符合链表特性:数组版希尔排序可以通过下标跳增量访问元素,但链表只能顺序遍历,你的代码强行模仿数组的下标访问,不仅效率低,还容易出错。

修正后的实现思路与代码

针对链表的特性,我们调整希尔排序的逻辑:对每个增量inc,将链表拆分为inc个子链表,对每个子链表执行插入排序。先修复moveptr函数,再重新实现排序逻辑。

第一步:修复moveptr函数

让它返回移动后的指针,这样就能正确获取指定位置的节点:

n* moveptr(n* ptr, int distance) {
    int i = 0;
    // 增加空指针判断,防止非法访问
    while (ptr != NULL && i < distance) {
        ptr = ptr->next;
        i++;
    }
    return ptr;
}

第二步:重新实现shellsort函数

这里采用交换节点数据的方式(比移动节点指针更简单,适合入门),逻辑和数组版插入排序一致,只是把数组下标访问换成链表的moveptr调用:

void shellsort(int size) {
    // 希尔排序增量序列,从size/2开始逐步减半
    for (int inc = size / 2; inc > 0; inc /= 2) {
        // 遍历每个需要插入的节点(从第inc个节点开始)
        for (int i = inc; i < size; i++) {
            // 获取当前要插入的节点和它的值
            n* current_node = moveptr(head, i);
            int current_val = current_node->data;

            // 往前找分组中的前一个节点位置
            int j = i - inc;
            n* prev_group_node = moveptr(head, j);

            // 分组内插入排序:把比current_val大的值往后移
            while (j >= 0 && prev_group_node->data > current_val) {
                // 找到前一个节点的下一个分组节点(j+inc位置)
                n* next_group_node = moveptr(prev_group_node, inc);
                // 把前一个节点的值移过去
                next_group_node->data = prev_group_node->data;

                // 继续往前找
                j -= inc;
                if (j >= 0) {
                    prev_group_node = moveptr(head, j);
                }
            }

            // 把current_val插入到正确位置
            if (j >= 0) {
                n* insert_pos = moveptr(prev_group_node, inc);
                insert_pos->data = current_val;
            } else {
                // j<0说明是分组里最小的元素,放到分组第一个位置
                moveptr(head, j + inc)->data = current_val;
            }
        }
    }
}

第三步:测试验证

运行你的主函数,比如输入5,再输入3 1 4 2 5,排序后会输出1-->2-->3-->4-->5-->,完美实现排序效果。

进阶优化思路

上面的实现用了交换数据的方式,虽然简单但每次moveptr都要从头遍历链表,效率不算最高。如果想进一步优化,可以直接移动节点指针,避免重复遍历找节点——需要找到当前节点在原链表中的前驱,再将节点插入到分组的正确位置,感兴趣的话可以尝试自己实现这个版本~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:53:33