对链表进行插入排序
对链表进行插入排序。
插入排序算法:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
到了链表,我们发现一个问题,那就是链表不能从后往前遍历,这就很尴尬了。我本来是尝试找到一个需要移动的节点(即该节点的值比前驱节点的值小),从前往后遍历,直到找到一个节点值比它大时插入到这个节点前面,然而实现了很久发现代码又臭又长,关键是还总有测试用例不通过,最后还是放弃了。
看了答案发现思路应该是创建一个辅助的新链表,并且使用一个指针遍历原链表,每次将原链表中的一个节点插入到新链表的合适位置(即该节点的值大于新链表上的节点的值,又小于后一节点的值)。最后将新链表的头部返回即可。代码如下,做了详细的注释,应该很容易看懂。
1 class ListNode { 2 int val; 3 ListNode next; 4 ListNode(int x) { 5 val = x; 6 } 7 } 8 /** 9 * 链表插入排序 10 * */ 11 public ListNode insertionSortList(ListNode head) { 12 //边界条件判断 13 if(head==null || head.next == null) 14 return head; 15 16 //创造一个新的链表头部 17 ListNode pre = new ListNode(-1); 18 //用一个临时变量保存头节点 19 ListNode ans = pre; 20 //cur是原链表上的指针 21 ListNode cur = head; 22 while (cur != null) { 23 //每次循环前重置pre为头结点,这样保证每次都从头往后遍历 24 pre = ans; 25 26 //当pre.next.val大于cur.val时停止循环 27 while (pre.next != null && pre.next.val < cur.val) { 28 pre = pre.next; 29 } 30 31 //pre.next.val 大于 cur.val,此时应该把cur插入到pre后 32 //保存原链表当前节点的下一节点 33 ListNode tmp = cur.next; 34 //把cur插入到pre之后 35 cur.next = pre.next; 36 pre.next = cur; 37 38 //cur指针后移一位 39 cur = tmp; 40 } 41 return ans.next; 42 }