对链表进行插入排序(C语言)

文章目录

【题目描述】
给定单个链表的头 head ,使用插入排序对链表进行排序,并返回排序后链表的头 。

插入排序算法的步骤:
1.插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
2.每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
3.重复直到所有输入数据插入完为止。

题目来源(力扣):对链表进行插入排序

示例1:
输入: head = [4,2,1,3]
输出: [1,2,3,4]

示例2
输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]

以下两种解法均涉及哨兵位的使用,以便于解决问题。

解法一

【基本思路】
另外设置一个带有哨兵位的链表,在单次插入中,在该链表对 head 节点的合适插入位置进行搜寻,找到后进行插入即可。再让 head 指向原链表的下一个节点,构成迭代。当原链表的所有节点都插入到该链表后(即 head 为空指针)时,插入排序完毕。
图解

【代码实现】

typedef struct ListNode ListNode;
struct ListNode* insertionSortList(struct ListNode* head){
    //空或者只有一个节点
    if(!head || !(head->next))
        return head;

    //设置哨兵位
    ListNode* dummy = (ListNode*)malloc(sizeof(ListNode));
    dummy->next = NULL;
    while(head)
    {
        ListNode* cur = dummy->next;
        ListNode* pre = dummy;
        //在带有哨兵位的链表中搜寻合适的插入位置
        while(cur && head->val > cur->val)  // 当cur为空指针时,是尾插
        {
            pre = cur;
            cur = cur->next;
        }
        //节点的插入
        pre->next = head;
        head = head->next;
        pre->next->next = cur;
    }

    head = dummy->next;
    free(dummy);
    dummy = NULL;
    return head;
}

解法二

【基本思路】
跟解法一不同的是,该解法直接在原链表上进行操作,跟数组的直接插入排序的实现十分类似,不过由于链表的修改涉及指针的指向问题强烈建议画图分析

不太了解数组的直接插入排序的朋友可以看一下这篇博客:带你了解直接插入排序

【代码实现】

typedef struct ListNode ListNode;
struct ListNode* insertionSortList(struct ListNode* head){
    //空或者只有一个节点
    if(!head || !(head->next))
        return head;

    //设置哨兵位
    ListNode* dummy = (ListNode*)malloc(sizeof(ListNode));
    dummy->next = head;
    //有序区间的尾节点
    ListNode* lastSorted = head;
    //待排序的节点
    ListNode* cur = head->next;
    while(cur)
    {
        //待排序的节点正好和有序区间尾节点构成有序
        if(lastSorted->val <= cur->val)
        {
            lastSorted = cur;
            cur = cur->next;
        }
        else  // cur->val < lastSorted->val
        {
            ListNode* pre = dummy;
            //寻找合适的插入位置
            while(pre->next->val <= cur->val)  // 取不取等均可
                pre = pre->next;
            //插入待排序的节点
            lastSorted->next = cur->next;
            cur->next = pre->next;
            pre->next = cur;
            
            cur = lastSorted->next;
        }
    }

    head = dummy->next;
    free(dummy);
    dummy = NULL;
    return head;
}

本专栏
有关链表的题目

其它专栏
有关数组的题目

链表实现直接插入排序是一种常用的排序算法。它可以通过修改链表中的指针来给出排序结果,而不需要移动元素。具体实现步骤如下: 1. 创建一个头结点,作为新链表的起点,并将原链表的第一个结点作为已排序的部分。 2. 从原链表中取下一个结点,将其插入到已排序链表中的正确位置,保持链表的有序性。 3. 重复步骤2,直到所有结点都被插入到已排序链表中。 具体的代码实现可以参考引用中给出的代码示例,其中使用了头结点和两个指针(p和q)来实现链表的插入操作。在每次插入结点后,可以通过输出链表的值来验证排序的进程。 需要注意的是,链表实现的直接插入排序算法不改变原链表元素的位置,而是在链表中给出其在排序表中的位置。这种算法适用于对链表进行排序的场景。 总结起来,链表实现直接插入排序的步骤包括: 1. 创建一个头结点,并将原链表的第一个结点作为已排序的部分。 2. 从原链表中取下一个结点,并将其插入到已排序链表中的正确位置。 3. 重复步骤2,直到所有结点都被插入到已排序链表中。 这样就可以利用链表实现直接插入排序算法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [基于双链表的直接插入排序、直接选择排序、冒泡排序](https://download.youkuaiyun.com/download/m0_62171658/86731089)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [直接插入排序算法之表插入排序详解](https://blog.youkuaiyun.com/sunnyoldman001/article/details/127080111)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [链表直接插入排序](https://blog.youkuaiyun.com/qq_41027398/article/details/122275622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值