链表14:单链表的排序
Posted 纵横千里,捭阖四方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表14:单链表的排序相关的知识,希望对你有一定的参考价值。
前面我们连续多节分析了链表反转的问题,你有没有注意到最大的问题都是指针要进行调整时的指向问题?具体又体现在两个方面,一个是反转相关的问题,一个是合并相关的问题,有些算法还是两个的结合。LeetCode148题又是一个典型的题目。
LeetCode148题 :给定一个无序单链表,实现单链表的排序(按升序排序)。
示例1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
思路:涉及到节点移动的场景,肯定少不了调整指针,这里还必须小心两端的处理。脑子不够还是画图来凑,画个图、走几步再写会比较好一些。这个题目同样有多种处理方式,一种是直接根据类似冒泡排序的方式硬写,但是很难写对,而且个大量改变指针会导致执行超时,是出力不讨好的事情。所以我们需要更加优化的方式。
1 偷梁换柱,通过数组排序再赋值回去
过程是这样的:首先循环一次获得链表的长度,然后创建一个数组。
再循环一次,将链表节点的值都赋值给数组对数组进行排序。
最后将数组的值再写回到链表里。
这样做是将链表问题变成了数组问题,也不矢为一种方法,代码就很好些了:
public ListNode sortInList(ListNode head) {
if(head == null) {
return head;
}
ListNode p = head;
ListNode q = head;
ListNode t = head;
int n = 0;
while (p != null) {
p = p.next;
n++;
}
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = head.val;
head = head.next;
}
//这里给我们省去了无数麻烦。如果有精力,可以现场自己实现一个
Arrays.sort(arr);
int i = 0;
while (q != null) {
q.val = arr[i++];
q = q.next;
}
return t;
}
2 归并排序法
上面的方法虽然能解决问题,但是面试官可能不满意,因为他就想考察你链表的控制能力。这里我们可以使用归并排序的方法来进行,先利用快慢指针找出链表的中点,然后分为两个链表,一直分,知道无法分为止,然后自底而上排序归并。
代码就是这样:
public ListNode sortInList (ListNode head) {
if(head == null || head.next == null)
return head;
//使用快慢指针找到中点
ListNode slow = head, fast = head.next;
while(fast!=null && fast.next !=null){
slow = slow.next;
fast = fast.next.next;
}
//分割为两个链表
ListNode newList = slow.next;
slow.next = null;
//将两个链表继续分割,这里必须用递归,否则一堆拆散的链表难以管理
ListNode left = sortInList(head);
ListNode right = sortInList(newList);
ListNode lhead = new ListNode(-1);
ListNode res = lhead;
//归并排序,如果想不明白,可以看完后面的经典排序专题再来看
while(left != null && right != null){
if(left.val < right.val){
lhead.next = left;
left = left.next;
}else{
lhead.next = right;
right = right.next;
}
lhead = lhead.next;
}
//判断左右链表是否为空
lhead.next = left!=null?left:right;
return res.next;
}
这个题目有自顶向下和自下而上两种方式,我们先熟练掌握一种吧。
3.利用冒泡方式进行排序
关键时刻如果想不到好的方式,根据题目硬写也可以的。这时候如果卷面整洁,思路清晰,能得个及格分,但是可能运行超时。
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
public ListNode sortInList (ListNode head) {
if(head==null)
return null;
ListNode oldP=head,oldHead ;
ListNode newHead=head;
while(oldP!=null){
oldHead=oldP;
oldP=oldP.next;
newHead= insertSeq(newHead,oldHead);
}
return newHead;
}
public ListNode insertSeq(ListNode newHead,ListNode oldHead){
//空
if(newHead==null){
return oldHead;
}
//最前面
if(newHead.val>=oldHead.val){
oldHead.next=newHead;
newHead=oldHead;
return newHead;
}
ListNode newCur=newHead;
//中间位置
while(newCur.val<oldHead.val && newCur.next!=null){
newCur=newCur.next;
}
oldHead.next=newCur.next;
newCur.next=oldHead;
return newHead;
}
}
以上是关于链表14:单链表的排序的主要内容,如果未能解决你的问题,请参考以下文章