Quick sort
Quick sorting embodies the idea of divide and conquer. Determine the final position of a number each time, place it in the correct position, and then quickly sort the arrays at both ends in the same way through recursion.
It should be noted that when using quick sort, the decision number needs to be taken randomly, which is called random selection comparator. Because when the array is ordered, the pointer will only brush from the end to the end, the efficiency of quick sorting will be very low, and the time complexity is O(n^2). Therefore, after randomly selecting the comparator, exchange the comparator with the leftmost number of the array, and then sort. In this way, even if the numbers are in order, the pointer will not brush from end to end.
- Quick sorting is an unstable algorithm. Algorithm instability means that two numbers are equal before sorting, but they may change the order after sorting.
Suppose the array to be sorted: a = [1, 2, 2, 3, 4, 5, 6];
In the random selection comparison sub (i.e. pivot) stage of quick sort:
If you select a[2] (that is, the second 2 in the array) as the comparator and place the numbers greater than or equal to the comparator in the large number array, a[1] (that is, the first 2 in the array) will be to the right of pivot, and the two 2 in the array are not in original order (this is "unstable").
If a[1] is selected as the comparator and the numbers less than or equal to the comparator are placed in the decimal array, the two 2 orders in the array are not the original order.
This shows that quick sort is unstable.
- Time complexity: O(nlogn), where n is the length of the array;
- Space complexity: O(logn). The space occupied here mainly comes from the stack space of recursive functions.
class Solution{ Random random = new Random(); public int[] sortArray(int[] nums) { quickSort(nums, 0, nums.length-1); return nums; } //Quick sort public void quickSort(int[] nums, int start, int last){ if(start<last){ int left = start, right = last; //Random access int ranIndex = random.nextInt(last-start+1)+start; int temp = nums[ranIndex]; nums[ranIndex] = nums[left]; nums[left] = temp; int aim = nums[left]; while(left<right){ while(left<right && aim<=nums[right]) right--; if(left<right) nums[left++] = nums[right]; while(left<right && nums[left]<=aim) left++; if(left<right) nums[right--] = nums[left]; } nums[left] = aim; quickSort(nums, start, left-1); quickSort(nums, left+1, last); } } }
Merge sort
Merging and sorting also embodies the idea of division and rule. Divide the sorting task into two sub arrays, and then merge the two sub arrays. When merging here, you need to apply for n more space resources to store the sorted array.
- Time complexity: O(nlogn)
- Space complexity: O(n)
class Solution { public int[] sortArray(int[] nums) { int[] buffer = new int[nums.length]; mergeSort(nums, 0, nums.length-1, buffer); return nums; } public void mergeSort(int[] nums, int start, int last, int[] buffer){ if(start<last){ int mid = (start+last)/2; mergeSort(nums, start, mid, buffer); mergeSort(nums, mid+1, last, buffer); mergeTwoArray(nums, start, mid, last, buffer); } } public void mergeTwoArray(int[] nums, int start, int mid, int last, int[] buffer){ int left = start, right = mid+1; int i = left; while(left<=mid && right<=last){ if(nums[left]<=nums[right]){ buffer[i++] = nums[left++]; } else{ buffer[i++] = nums[right++]; } } while(left<=mid) buffer[i++] = nums[left++]; while(right<=last) buffer[i++] = nums[right++]; for(int j = start; j<=last; j++){ nums[j] = buffer[j]; } } }
Select sort
Selective sorting is suitable for occasions where the cost of data exchange is relatively high. Remember the smallest subscript in the unordered array in each round. After traversing the array, exchange the smallest subscript number with the next number after sorting (unordered number).
- Time complexity: O(n^2)
- Space complexity: O(1)
public class Solution { // Selection sorting: the smallest element of each round of selection is exchanged to the beginning of the unscheduled part public int[] sortArray(int[] nums) { int len = nums.length; // Loop invariant: [0, i) ordered, and all elements in the interval are finally scheduled for (int i = 0; i < len - 1; i++) { // Select the index of the smallest element in the interval [i, len - 1] and exchange it to the subscript i int minIndex = i; for (int j = i + 1; j < len; j++) { if (nums[j] < nums[minIndex]) { minIndex = j; } } swap(nums, i, minIndex); } return nums; } private void swap(int[] nums, int index1, int index2) { int temp = nums[index1]; nums[index1] = nums[index2]; nums[index2] = temp; }
Insert sort
The more ordered the array is, the more efficient and orderly the insertion sorting is. The fewer times the pointer needs to be moved, at least n times.
Insert sorting starts from the next number (unordered number) of the sorted array on the left. Compare it with the number of the sorted array one by one. If the unordered number is smaller, move the large sorted number back one grid until you find your own position.
class Solution{ public void InsertSort(int[] nums){ for(int i = 0; i<nums.length; i++){ int temp = nums[i]; int j = i; while(j>0 && nums[j-1]>temp){ nums[j] = nums[j-1]; j--; } nums[j] = temp; } } }