题目

插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/insertion-sort-list
思路
自己的思路
首先,插入排序没什么可说的,就是在一个已排好序的数据中不断插入数据,这里的难点就是在单链表中进行插入排序,一开始我想的是设置两个指针,一个最小指针,放在头部,一个最大指针,放在尾部,这样就能少了很多判断条件,所以代码如下:
ListNode* insertionSortList(ListNode* head) {
if (head == NULL)
return NULL;
if (head->next == NULL)
return head;
ListNode* res =new ListNode(INT_MIN);
ListNode* end = new ListNode(INT_MAX);
ListNode* H = head->next;
res->next = head;
head->next = end;
head = H;
ListNode* start = res;
ListNode* temp, * node;
while (head != NULL) {
temp = head->next;
while (start->next&&head->val > start->next->val)
start=start->next;
node = start->next;
start->next = head;
head->next = node;
start = res;
head = temp;
}
while (start->next->next)
start = start->next;
start->next = NULL;
return res->next;
}
这种思路存在的不足就是对于最后一个最大指针如何删除的问题,我使用的方法就是再遍历一遍排好序的链表,最后将最大指针删除即可,多了一遍循环,所以时间复杂度不是最优,代码也不够简洁明了。
参考思路
改进上诉思路的一种方法就是:我们同样是设置两个头尾指针,用于表示已排好序的链表,那么头指针就是新建一个头节点指针,尾指针就是head,具体代码如下:
ListNode* insertionSortList(ListNode* head) {
ListNode* start = new ListNode(0);//设置头节点指针
ListNode* temp;
start->next = head;
//该思路就是设置排序好的链表中的头,尾指针,头指针就是前面所设置的,尾指针就是head
while (head && head->next) {
if (head->val <= head->next->val) {//如果要比较的节点值大于head,则不用排序
head = head->next;
continue;
}
temp = start;
while (head->next->val > temp->next->val)//否则进入内循环进行排序
temp = temp->next;
ListNode* curr = head->next;//保存下一个待插入的节点
head->next = curr->next;//这里是移除要插入的节点,否则将会造成重复
curr->next = temp->next;
temp->next = curr;
}
return start->next;
delete start;
}
这里巧妙的地方在于将已排序的链表的尾指针设置为head,那么每次将要排序的节点就是head->next,如果待排序的节点值大于此时的尾节点,那么就不用再和组内的节点进行比较了,直接进行下一次的循环;否则,就进入内循环,逐个比较,知道找到合适的位置。这种思路理解的重点在于下面几个:
if (head->val <= head->next->val) {//如果要比较的节点值大于head,则不用排序
head = head->next;
continue;
}
这里巧妙的地方在于尾指针和待插入的节点是相连接的,这样当待插入的节点大于尾指针时,则直接将此时待插入的节点更新为尾节点即可
还需注意的一个问题是:在我们每次准备进入内循环时,必须要保证是从头节点开始的,所以设置:
temp = start;
还有就是内循环的判断条件:
while (head->next->val > temp->next->val)//否则进入内循环进行排序
temp = temp->next;
因为待插入的点已经判断出小于尾指针,那么在已排序的链表中一定能将该节点插入。
总结
这道题是关于插入排序在单链表中的应用,相比较在数组来说,因为单链表无随机访问性,所以在解题过程中我们可以尽量朝着数组类型的插入排序靠,理解这道题的一个难点和重点就是关于设置头尾指针的问题,一种巧妙的方法就是将尾指针设置为head,这样在待插入的节点大于已排好序的单链表中的最后一个节点时,就不用再进入内循环比较,直接进行下一次的插入操作,简化了很多步骤和代码。
365

被折叠的 条评论
为什么被折叠?



