链表的特点决定了只能从前往后的遍历,我的第一个思路是冒泡排序,但是超时,看了一眼归并排序的写法,真的是妙啊。
1 冒泡(未通过)
public ListNode sortInList (ListNode head) {
// write code here
ListNode res=null;
if(head==null){
return res;
}
int nodeNum=0;
ListNode p=head;
while(p!=null){ //遍历链表获得链表节点数,节点数是用来控制沉降次数,9个节点,沉降8次
nodeNum++;
p=p.next;
}
for(int i=nodeNum-1;i>0;i--){
int count=i; //控制这一次沉降的结束边界,后面的就不用沉降了已经是有序了
ListNode p1=head;
ListNode p2=head.next;
while(count>0){
if(p1.val>p2.val){//值交换
int tmp=p1.val;
p1.val=p2.val;
p2.val=tmp;
}
p1=p1.next;
p2=p2.next;
count--;
}
}
res=head;
return res;
}2 归并排序
public ListNode sortInList (ListNode head) {
// write code here
ListNode res=null;
if(head==null){
return res;
}
return mergeSort(head);
}
public ListNode mergeSort(ListNode head){
if(head==null || head.next==null){ //最后没有节点或者最后还有一个节点,返回本身,一个节点本身就是有序了,不用排了
return head;
}
ListNode slow=head;
ListNode fast=head.next.next; //上面已经排除了1个节点的请情况,所以这里至少有两个节点,head.next.next 存在
ListNode head1=head;
while(fast!=null && fast.next!=null){ //两个节点不用进去循环,假如我们让进去循环的话,fast为null,fast.next 作为条件就报错。
slow=slow.next;
fast=fast.next.next;
}
ListNode head2=slow.next; //先保存后面链表的头节点
slow.next=null;//将前面链表断开形成真正的两条链表
ListNode left=mergeSort(head1);
ListNode right=mergeSort(head2);
return mergeList(left,right);
}
public ListNode mergeList(ListNode l1,ListNode l2 ){//这里比较巧妙,这是一个针对有序链表的写法,但是我们的拆分明明是不能保证有序的,哈哈,巧在当我们在不停的分治的过程中,最后一定是有单节点的合并的,两个单节点可以认为就是两个有序的链表,两个单节点的合并就是两个有序链表的合并,也就是说两个单节点链表合并成了一个拥有两个节点的有序链表,再继续向上回溯,从下网上就形成了两个有序链表的合并了。
ListNode node=new ListNode(0);
ListNode p=node;
while(l1!=null||l2!=null){
if(l1!=null && l2!=null){
if(l1.val<l2.val){
p.next=l1;
l1=l1.next;
p=p.next;
}else{
p.next=l2;
l2=l2.next;
p=p.next;
}
}else if(l1==null){
p.next=l2;
l2=l2.next;
p=p.next;
}else if(l2==null){
p.next=l1;
l1=l1.next;
p=p.next;
}
}
return node.next;
}
京公网安备 11010502036488号