题目描述
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
示例
输入: 4->2->1->3
输出: 1->2->3->4
输入: -1->5->3->4->0
输出: -1->0->3->4->5
解题思路
1.若为双链表(每个节点有其前驱),那么很容易模拟数组中的插入排序(从右往左插入);
而对于单链表,只能用pre每次从开头开始依次比较,而tail指向的是已经排好序的最后一个元素的位置
java代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
private class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public ListNode insertionSortList(ListNode head) {
if(head == null){
return null;
}
ListNode dummyNode = new ListNode(Integer.MIN_VALUE);
dummyNode.next = head;
ListNode pre = dummyNode; //虚拟头结点
ListNode cur = head.next;
ListNode tail = head; //tail指向的是排序好的节点的最后一个位置
while (cur !=null){
//pre.next != cur表明cur不处在原位置
while (pre.next != cur && pre.next.val <= cur.val){
pre = pre.next;
if(pre.next != null && pre.next.val > cur.val){ //找到pre为待插入位置的前一个位置
break;
}
}
if(pre.next == cur){ //即cur原位置即为排序后的正确位置
tail = cur; //更新tail
cur = tail.next; //取下一个元素进行插入排序
pre = dummyNode;
}else { //找到排序位置非原位置
tail.next = cur.next; //tail指向下一个待排序元素
cur.next = pre.next;
pre.next = cur; //这两句是把cur排到pre后面,即为cur找到了正确位置
cur = tail.next; //更新
pre = dummyNode;
}
}
head = dummyNode.next;
dummyNode.next = null; //方便JVM回收
return head;
}
}
运行结果如下:
2.优化
每次拿出待排序的节点,先用前面已排序好的最后一个元素进行比较,如果大于或者等于它,就不用排序了,直接进入下一次循环即可;否则,就用pre从头开始遍历比较。
java代码如下:
class Solution {
public ListNode insertionSortList(ListNode head) {
ListNode dummy = new ListNode(Integer.MIN_VALUE), pre;
dummy.next = head; //head指针指向当前已排序的最后一个位置
while(head != null && head.next != null) { //还有待排序元素
if(head.val <= head.next.val) { //原位置即为排序后的正确位置
head = head.next;
continue;
}
pre = dummy;
while (pre.next.val < head.next.val){//pre最后指向待插入位置的前一个节点
pre = pre.next;
}
ListNode cur = head.next;
head.next = cur.next;
cur.next = pre.next;
pre.next = cur;
}
head = dummy.next;
dummy.next = null;
return head;
}
}
运行结果如下: