对链表进行插入排序(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; }
本专栏
其它专栏