您的位置:首页 > 其它

链表排序

2016-07-12 09:27 267 查看

题目

在 O(n log n) 时间复杂度和常数级的空间复杂度下给链表排序。

您在真实的面试中是否遇到过这个题? Yes

样例

给出 1->3->2->null,给它排序变成 1->2->3->null.

解题

尝试快速排序,划分节点不知道怎么找

参考链接

快速排序

找到小于x,找到等于x,找到大于x,三个链表合并

注意:

如果小于x和等于x的在一起考虑,有错误

如:1 3 2

第一次划分 成1 和3 2

3 2 始终 是划分在一起,出现栈溢出

/**
* Definition for ListNode.
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int val) {
*         this.val = val;
*         this.next = null;
*     }
* }
*/
public class Solution {
/**
* @param head: The head of linked list.
* @return: You should return the head of the sorted linked list,
using constant space complexity.
*/
public ListNode sortList(ListNode head) {
// write your code here
if(head == null)
return head;
ListNode sortList = quickSort(head);
return sortList;

}

public ListNode quickSort(ListNode head){
if(head==null || head.next==null)
return head;

ListNode lowHead = new ListNode(0);
ListNode low = lowHead;
ListNode highHead = new ListNode(0);
ListNode high = highHead;

ListNode midHead = new ListNode(0);
ListNode mid = midHead;
ListNode p = head;
int x = p.val;
while(p!=null){
if(p.val <x){
low.next = p;
low = low.next;
}else if(p.val >x){
high.next = p;
high = high.next;
}else{
mid.next = p;
mid = mid.next;
}

p = p.next;
}
low.next = null;// 断开
mid.next = null;
high.next = null;
ListNode l1 = quickSort(lowHead.next);
ListNode l2 = quickSort(highHead.next);
ListNode merge = concat(l1,midHead.next,l2);
return merge;

}
public ListNode concat(ListNode low,ListNode mid,ListNode high){
ListNode lowLast = getLastNode(low);
ListNode midLast = getLastNode(mid);
if(low==null){
midLast.next = high;
return mid;
}
lowLast.next = mid;
midLast.next = high;
return low;
}
public ListNode getLastNode(ListNode head){
if(head ==null)
return head;
ListNode last = head;
while(last.next!=null){
last = last.next;
}
return last;
}
}


上面链接中给了归并排序算法

public ListNode mergeSort(ListNode head){
if(head == null || head.next == null)
return head;
ListNode mid = findMiddle(head);
ListNode right = sortList(mid.next); // 先右边排序
mid.next = null;// 断开
ListNode left = sortList(head);

return merge(left, right);
}
private ListNode merge(ListNode head1, ListNode head2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (head1 != null && head2 != null) {
if (head1.val < head2.val) {
tail.next = head1;
head1 = head1.next;
} else {
tail.next = head2;
head2 = head2.next;
}
tail = tail.next;
}
if (head1 != null) {
tail.next = head1;
} else {
tail.next = head2;
}

return dummy.next;
}

public ListNode findMiddle( ListNode head){
ListNode slow = head;
ListNode fast = head;
while(fast!=null && fast.next!=null && fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}


桶排序

min - max之间的数转化成a - b 之间的方式

一般归一化的方式:max−valmax−min \frac{max - val}{max - min}

可以发现:min转化成 1 ,max转化成 0

下面需要将其转化到:a-b之间

一般认为是这样转化:

a+rand(0,1)∗(b−a)a+ rand(0,1)*(b-a),这里的rand就是上面的归一化方式

但是还是会发现max转化成最小值,min转化成最大值

桶排序要使较大的数放在大桶号,较小的数放在小桶号

上面等式还需要改变

b−rand(0,1)∗(b−a)b - rand(0,1)*(b-a)

这样就好了

public class Solution {
/**
* @param head: The head of linked list.
* @return: You should return the head of the sorted linked list,
using constant space complexity.
*/
public ListNode sortList(ListNode head) {
// write your code here
if(head == null)
return head;
ListNode sortList = bucketSort(head);
return sortList;

}
public ListNode bucketSort(ListNode head){
if(head == null || head.next == null)
return head;
int min = getMin(head);
min = min>0?min:0;
int max = getMax(head);
max = max>0?max:0;
int N = 14;
int a = 0;
int b = N-1;
ListNode[] bucket = new ListNode
;
for(int i=0;i<N;i++){
bucket[i] = new ListNode(0);
}
ListNode p = head;
while(p!=null){
int val  = p.val;
int index = val%N;
ListNode pNext = p.next;
if(val<0)
index =0;
else{
index = b - (b-a)*(max - val)/(max - min);
}
insertList(bucket[index],p);
p = pNext;
}
ListNode sortHead = new ListNode(0);
ListNode cur = sortHead;
for(int i=0;i<N;i++){
ListNode bk = bucket[i].next;
while(bk!=null){
cur.next = bk;
cur = cur.next;
bk = bk.next;
}
}
return sortHead.next;
}
public int getMax(ListNode head){
ListNode p = head;
int max = p.val;
while(p!=null){
max = max<p.val?p.val:max;
p = p.next;
}
return max;
}

public int getMin(ListNode head){
ListNode p = head;
int min = p.val;
while(p!=null){
min = min>p.val?p.val:min;
p = p.next;
}
return min;
}
// 有头节点的插入
public void insertList(ListNode head,int val){
ListNode insertNode = new ListNode(val);
insertNode.next =null;
ListNode prev = head;
// 插入在头
if(prev.next==null){
prev.next = insertNode;
return;
}

// 插入在中间
while(prev.next!=null){
if(prev.next.val<=val){
prev = prev.next;
}else{
insertNode.next = prev.next;
prev.next = insertNode;
return;
}
}
// 插入在末尾
prev.next = insertNode;

}

// 有头节点的插入
public void insertList(ListNode head,ListNode o){
ListNode insertNode = o;
ListNode prev = head;
if(prev.next==null){
prev.next = insertNode;
prev = prev.next;
prev.next =null;
return;
}

int val = insertNode.val;
while(prev.next!=null){
if(prev.next.val<=val){
prev = prev.next;
}else{
insertNode.next = prev.next;
prev.next = insertNode;
return;
}
}
// 插入在末尾
prev.next = insertNode;
prev = prev.next;
prev.next =null;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: