对链表进行插入排序。
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* insertionSortList(struct ListNode* head){
//系统会很贼地输入空的head,然后就会报错,很烦,以防这种情况
if (head==NULL) return head;
//可能有插入头结点之前的情况,有虚拟头结点dummyhead作为前驱节点,可以更方便进行插入
struct ListNode* dummyhead=(struct ListNode *)malloc(sizeof(struct ListNode));
//赋值,防止内存泄露,反正接下来也用不到
dummyhead->val=0;
//dummyhead的下一节点指向head
dummyhead->next=head;
//创建指向已排序链表尾部的指针节点tail,默认指向头节点
//就像选择排序要先定义个用来比较的参照物一样
struct ListNode* tail=head;//获取head所有元素
//node指向待排序的节点,tail所指的head就当做排好了,看下一个就行了
struct ListNode* node=head->next;
//当node指向空.就结束循环,这里省略了"=NULL"
while(node)
{
//如果待排序的节点正好大于尾节点tail,天助我也,这不就正好排完序了嘛
if(node->val>tail->val)
{
//既然算排完序了,尾指针tail也就指向下一个节点了
tail=tail->next;
//待排序节点node也指向下一个
node=node->next;
//下面的语句是待排序节点小于尾节点的情况,无需再执行,进入下一循环
continue;
}
//定义一个用来比较的节点指针compare
//每次比完都会返回头部
struct ListNode* compare=dummyhead;
//因为dummyhead->next=head,dummyhead的next才是head
//这里用compare->next,这样就指向首位的节点了
//如果指针所指的值比待排序的值小,那就继续往下走
//直到compare->next的值比node的的值大
while(compare->next->val<node->val) compare=compare->next;
//下面就是接线操作了
//尾节点tail的本来是指node的
//为了把node挪出来,tail指向node的下一节点node->next,防止丢失
tail->next=node->next;
//node->next不用指向原本的下一节点了
//此时compare->next指向的是比node大的数,所以node开始认compare->next做老大哥
//node->next接上了老大哥compare->next,和原本的位置撇清了关系
node->next=compare->next;
//比node小的compare地位迅速降低,泪目
//只能乖乖接上老二哥node,也只敢通过node和原本的大哥compare->next联系
//如此一来,node就成功混进两者之间
compare->next=node;
//node掌握别的值,又开始新一轮的接线操作,一场腥风血雨又在酝酿(可以出本书了)
node=tail->next;
}
//dummyHead链表的表头,dummyHead->next会指向链表的第一个节点
return dummyhead->next;
}
如有错误,还望指正,十分感谢!
走了点弯路,看了一些大佬的代码,就很很顺了,最大的收获是对链表更熟悉了,有空写个链表相关的项目巩固一下
题目来源:
力扣(LeetCode)
题目链接:
https://leetcode-cn.com/problems/insertion-sort-list