各种排序笔记---基于比较排序部分
1. 选择排序 selection sort
大循环 从左到右每次以一个点开始扫描array
小循环 找到从当前起始点开始的最小值
时间复杂度为O(N^2)
//selection sort an array array[] public class Solution { public int[] solve(int[] array) { if (array == null || array.length == 0) { return array; } for (int i = 0; i < array.length - 1; i++) { int gobalMin = i; for (int j = i + 1; j < array.length; j++) { if (array[j] < array[gobalMin]) { gobalMin = j; } } swap(array, i, gobalMin); } return array; } private void swap(int[] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } }
2. 归并排序 Merge sort
归并排序是基于一种被称为“分治”(divide and conquer)的策略。
Merge sort array:
public int[] mergeSort(int[] array) { if (array == null || array.length == 0) { return array; } int[] temp = new int[array.length]; mergeSortHelper(array, 0, array.length - 1, temp); return array; } private void mergeSortHelper(int[] array, int start, int end, int[] temp) { if (start == end) { return; } int mid = start + (end - start) / 2; mergeSortHelper(array, start, mid, temp); mergeSortHelper(array, mid + 1, end, temp); merge(array, start, mid, end, temp); } private void merge(int[] array, int start, int mid, int end, int[] temp) { int left = start; int right = mid + 1; int index = start; while (left <= mid && right <= end) { if (array[left] < array[right]) { temp[index++] = array[left++]; } else { temp[index++] = array[right++]; } } while (left <= mid) { temp[index++] = array[left++]; } while (right <= end) { temp[index++] = array[right++]; } for (index = start; index <= end; index++) { array[index] = temp[index]; } }
复杂度分析:
1 2 3 4 5 6 7 8
/ 当前层拆分需要劈1刀 O(1)
1 2 3 4
/ 当前层拆分需要劈2刀 O(2)
12 ...
/
1 当前层拆分需要劈n /2刀
1 + 2 + 4 + 8+ ... + n/2 -> n = O(n) 可以这样理解,终极状态下每个数字被切分成一个单位,n个数字,需要被切n-1刀
所以devide and conquer的上半部分的时间复杂度是O(n) 而不是log(n)
空间复杂度:考虑计算机里面只要保存的额外开销,其实是粉色部分,因为在任意时刻,计算机只有一个确定的状态,call stack在同一个确定的层只能保留部分的结果。比如最底层只能保留1,或者保留2,而不会1,2同时在栈里面!
所以空间复杂度:1 + 2 + 4 + 8 + ... + n = O(2n) = O(n)
==============================================
devide and conquer的上半部分,merge 部分, totoal time complexity is O(nlogn):
1 2 3 4 5 6 7 8
\/ \/ \/ \/ this level time complexity is O(n)
12 34 56 78
\ / \ / this level time complexity is O(n)
1234 5678
\ / this level time complexity is O(n)
12345678
3. 快速排序
Array quick sort:
重点在于理解左右两个挡板的物理意义!!!
a. [0,....., left]: left 的左侧(不包含left)全部为比pivot小的数
b. [left, right]: left 和 right之间为未探索的区域
c. [right, ..... n-1]: right的右侧(不包含)全部为比pivot大或者等于的数字
public class Solution { /** * @param A an integer array * @return void */ public void sortIntegers2(int[] A) { quickSort(A, 0, A.length - 1); } private void quickSort(int[] A, int start, int end) { if (start >= end) { return; } int left = start, right = end; // key point 1: pivot is the value, not the index int pivot = A[(start + end) / 2]; // key point 2: every time you compare left & right, it should be // left <= right not left < right while (left <= right) { // key point 3: A[left] < pivot not A[left] <= pivot while (left <= right && A[left] < pivot) { left++; } // key point 3: A[right] > pivot not A[right] >= pivot while (left <= right && A[right] > pivot) { right--; } if (left <= right) { int temp = A[left]; A[left] = A[right]; A[right] = temp; left++; right--; } } quickSort(A, start, right); quickSort(A, left, end); } }
伪代码:
function quicksort(q) var list less, pivotList, greater if length(q) ≤ 1 { return q } else { select a pivot value pivot from q for each x in q except the pivot element if x < pivot then add x to less if x ≥ pivot then add x to greater add pivot to pivotList return concatenate(quicksort(less), pivotList, quicksort(greater)) }
Linkedlist quick sort
public class Solution { public ListNode sortList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode mid = findMedian(head); // O(n) //new three dummmy node with a tail point to it ListNode leftDummy = new ListNode(0), leftTail = leftDummy; ListNode rightDummy = new ListNode(0), rightTail = rightDummy; ListNode middleDummy = new ListNode(0), middleTail = middleDummy; //sprate to three part while (head != null) { if (head.val < mid.val) { leftTail.next = head; leftTail = head; } else if (head.val > mid.val) { rightTail.next = head; rightTail = head; } else { middleTail.next = head; middleTail = head; } head = head.next; } //make the tail to null leftTail.next = null; middleTail.next = null; rightTail.next = null; //recurisive do the sort ListNode left = sortList(leftDummy.next); ListNode right = sortList(rightDummy.next); //connect the three parts together return concat(left, middleDummy.next, right); } private static ListNode findMedian(ListNode head) { ListNode fast = head.next; ListNode slow = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } private static ListNode concat(ListNode left, ListNode mid, ListNode right) { ListNode dummy = new ListNode(0), dummyTail = dummy; dummyTail = connect(dummyTail, left); dummyTail = connect(dummyTail, mid); dummyTail = connect(dummyTail, right); return dummy.next; } private static ListNode connect(ListNode dummyTail, ListNode current) { while (current != null) { dummyTail.next = current; dummyTail = dummyTail.next; current = current.next; } return dummyTail; } }
相关题目整理: //to do