Sort the list
0. Source
Source: stay button (LeetCode)
Topic link: https: //leetcode-cn.com/problems/sort-list
1. Title Description
Complexity and the spatial complexity of constant grade, are sorted linked list in O (n log n) time.
2. Test Case
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
3. Problem-solving ideas
3.1 The general idea
See list sorted, my first reaction is to should be able to achieve, mainly because I have this idea of solving the problem, I will not speak the time complexity and space complexity of what I feel is the selection sort or insertion sort should be able to achieve the sort of list
Talk is cheap show me the code..
Well, the pseudo-code. (Since I mainly use the Java programming, so I use Java to achieve a)
while(没有到最后一个节点){
Node cursorNode = currentNode.next;
while( cursorNode != null){
把找到比第一层循环节点的小的节点与它进行交换
cursorNode = cursorNode.next;
}
}
It is probably the case, and selection sort almost achieved.
But look at the subject: the need for time complexity complexity O (n log n) there is a constant level of space, the need for time complexity, reminds me of merge sort, a look is also not figured out, but looked over the array the solution to a problem and merge sort bigwigs on LeetCode it clear thinking, here is merge sort of the basic ideas
3.2 Description merge sort ideas
3.2.1 The basic idea
The overall generalization is recursively split from top to bottom, from bottom to top and then merge gradually.
- Recursive partitioning :
First array to be sorted into left and right sub-sequences, then two left and right sequences are split into four sub-sequences, and so on until the smallest number of elements in the sequence to a two or far.
- Gradually merge :
The bottom of a subsequence leftmost sort will be ordered from left to right and a second sub-sequence, then the two sequences were combined and sorted ordered, from left to right and then the bottom third ..... subsequences sort memory after completion of the merger of the sort operation in the array (must pay attention to the hierarchy from the combined, can be understood as a recursive hierarchy return)
3.2.2 algorithm steps
- Space applications, so that the size of the sum of two sorted sequences, the sequence space used to store the merged;
- Setting two pointers, respectively, the first position of the starting position of the two sorted sequence;
- Comparison of two pointer points to an element, the selected element into a relatively small space to merge, and move the cursor to the next position;
- Repeat step 3 until the pointer reaches one end of the sequence;
- All remaining elements of another sequence directly copied to the merging of the sequence.
3.2.3 dynamic presentation
3.2.4 algorithm properties
And selection sort, like merge sort of performance affected by the input data, but the performance is much better than selection sort, as is always O (nlogn) time complexity. The cost of additional memory space is needed.
3.2.5 code shows
/**
* 递归拆分
* @param arr 待拆分数组
* @param left 待拆分数组最小下标
* @param right 待拆分数组最大下标
*/
public static void mergeSort(int[] arr, int left, int right) {
int mid = (left + right) / 2; // 中间下标
if (left < right) {
mergeSort(arr, left, mid); // 递归拆分左边
mergeSort(arr, mid + 1, right); // 递归拆分右边
sort(arr, left, mid, right); // 合并左右
}
}
/**
* 合并两个有序子序列
* @param arr 待合并数组
* @param left 待合并数组最小下标
* @param mid 待合并数组中间下标
* @param right 待合并数组最大下标
*/
public static void sort(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1]; // 临时数组,用来保存每次合并年之后的结果
int i = left;
int j = mid + 1;
int k = 0; // 临时数组的初始下标
// 这个while循环能够初步筛选出待合并的了两个子序列中的较小数
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 将左边序列中剩余的数放入临时数组
while (i <= mid) {
temp[k++] = arr[i++];
}
// 将右边序列中剩余的数放入临时数组
while (j <= right) {
temp[k++] = arr[j++];
}
// 将临时数组中的元素位置对应到真真实的数组中
for (int m = 0; m < temp.length; m++) {
arr[m + left] = temp[m];
}
}
3.3 merge sort list Precautions
1. Locate the intermediate node
Solution: This method is slow fast speed dual-use [] pointer to complete, and, in fact, the principle is particularly easy on the pricey sounds great, every move is a backward one, the other two to move back, definitely the last first-pointer fast and slow pointer twice. This and running, as if a man twice your speed is, at the same time, he must be your journey twice.
The intermediate node number of the node can also be separated, if an odd number, the intermediate node is the middle, if it is an even number of intermediate nodes is a node before the intermediate position, in fact, the pointer to slow it as an intermediate node.
2. disconnected from the intermediate node, respectively, and these two lists sorted by
How to Disconnect: the pointer is to slow the next node with a node to hold down the starting node as the right of the list, and slow the next pointer is set to null
4. The code implementation
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public class LinkListSort {
public static ListNode sortList(ListNode head) {
// 设置递归终止条件:如果是一个节点,或者是 null 就可以返回
if ( head == null || head.next == null)
{
return head;
}
// 通过 快慢双指针 来寻找链表分割的点
ListNode slowNode = head;
ListNode fastNode = head.next;
while (fastNode!=null && fastNode.next!=null)
{
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
// 设置右部分链表的开始部分
ListNode temp = slowNode.next;
// 从中间断开链表
slowNode.next = null;
ListNode leftNode = sortList((ListNode) head);
ListNode rightNode = sortList((ListNode) temp);
//设置一个新的头节点来保存排序后的效果
ListNode cursorNode = new ListNode(0);
ListNode resNode = cursorNode;
// 对两个链表进行排序
while ( leftNode!=null && rightNode!=null)
{
if(leftNode.val < rightNode.val)
{
cursorNode.next= leftNode;
leftNode = leftNode.next;
}else{
cursorNode.next = rightNode;
rightNode = rightNode.next;
}
// 将指针节点向后移动
cursorNode = cursorNode.next;
}
// 判断两条链表是否循环到结尾,如果没循环到结尾将未循环完的挂在上面
cursorNode.next = leftNode == null ? rightNode : leftNode;
return resNode.next;
}
public static void main(String[] args) {
ListNode head = new ListNode(4);
ListNode a = new ListNode(2);
ListNode b = new ListNode(1);
ListNode c = new ListNode(3);
head.next =a;
head.next.next = b;
head.next.next.next=c;
ListNode listNode = sortList2( head);
while ( listNode!=null )
{
System.out.print(listNode.val+" ");
listNode = listNode.next;
}
}
}
5. Summary
1. learn the slow and fast two-pointer,
the advantages as well as merge sort 2. Use the pointer above do not apply in the space, so there is no wasted space array, simply tailored to the list sorting algorithm.