刷题笔记3:链表的插排
思路:对一个无头结点的链表进行插排时,设置一个哑节点指向链表第一个元素,方便将元素插入到第一个元素之前。且整个过程需要用到三个指针来操作。
分别为:有序列表最后一个元素、链表中当前比较元素、从头开始遍历链表的指针
时间复杂度为O(n^2),空间复杂度为O(1).
题目:
代码:
class Solution {
public ListNode insertionSortList(ListNode head) {
//若链表为空,直接返回
if(head==null||head.next==null){
return head;
}
//该题中head其实就是一个元素,没有用处,不能当基准指针,也不能在排序过程中做辅助指针,所以需要自己定义的指针有点多
ListNode darkNode=new ListNode(0);//因为该链表的head也是要进行排序的,所以定义一个假头,方便往假头和第一个元素中间插入
darkNode.next=head;
ListNode lastNode=head;//将第一个元素当作链表已经排序好的最后一个元素
ListNode cur=head.next;//当前要排序的节点
ListNode firstNode=darkNode;//定义一个便于从前遍历链表,找到合适插入位置的前一个节点的指针
//凡进循环的都是链表至少存在两个节点,所以一开始就要先执行插入寻找操作,而非判断循环退出条件
while(cur!=null){
if(cur.val>=lastNode.val){
lastNode=lastNode.next;
cur=cur.next;
}else{
while(cur.val>=firstNode.next.val){
firstNode=firstNode.next;
}
//找到位置,完成插入
lastNode.next=cur.next;
cur.next=firstNode.next;
firstNode.next=cur;
//将辅助指针归位
firstNode=darkNode;
//cur指针指向下一个节点,继续排序
cur=lastNode.next;
}
}
return darkNode.next;
}
}
偷懒做法:能解题,但是没用插排,用的快排
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
ListNode h1=head;
int count=0;
//若链表为空或者只有一个元素,直接返回
if(head==null){
return head;
}
while(true){
if(h1!=null){
count++;
h1=h1.next;
}else{
break;
}
}
h1=head;
int[] temp=new int[count];
for(int i=0;i<count;i++){
temp[i]=h1.val;
h1=h1.next;
}
h1=head;
Arrays.sort(temp);
for(int i=0;i<count;i++){
h1.val=temp[i];
h1=h1.next;
}
return head;
}
}