Table of contents
Stability of the sorting algorithm : If elements of the same size have the same relative position before and after sorting, it is called a stable sorting.
Note: A sorting that is inherently stable can be implemented as an unstable sorting; but conversely, a sorting that is inherently unstable cannot be implemented as a stable sorting.
Stable sorting algorithm : insertion sort, bubble sort, merge sort
Bubble Sort
Time complexity: o(n^2) If optimization is added, the best case is O(N)
Space complexity: O(1)
Stability: Stable
public static void bubbleSort(int[] array){
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1; j++) {
if (array[j] > array[j+1]) {
swap(array, j, j+1);
}
}
}
}
private static void swap(int[] array, int minIndex, int i) {
int tmp = array[i];
array[i] = array[minIndex];
array[minIndex] = tmp;
}
optimization:
public static void bubbleSort(int[] array) {
for (int i = 0; i < array.length-1; i++) {
boolean flg = false;
for (int j = 0; j < array.length-1-i; j++) {
if(array[j] > array[j+1]) {
swap(array,j,j+1);
flg = true;
}
}
if(!flg) {
return;
}
}
}
Heap sort
Time complexity: O(n*logN) N^1.3 -->
Space complexity: O(1)
Stability: Unstable
When the amount of data is very large, heap sorting must be faster than Hill's heap
sorting principle:
- Swapping the top element of a large root heap with the last element
- Decrease the length of an array by one
- After re-adjusting the heap into a large root heap
public static void heapSort(int[] array){
createHeap(array);
for (int i = 0; i < array.length - 1; i++) {
swap(array, 0, array.length-1-i);
shiftDown(array, 0, array.length-1-i);
}
}
private static void createHeap(int[] array) {
for (int i = (array.length-1-1)/2; i >= 0; i--) {
shiftDown(array, i, array.length);
}
}
private static void shiftDown(int[] array, int i, int length) {//length个元素
int child = i * 2 + 1;
while (child < length) {
if (child + 1 < length && array[child] < array[child+1]) {
child++;
}
if (array[child] > array[i]) {
swap(array, child, i);
i = child;
}else {
break;
}
child = i * 2 + 1;
}
}
private static void swap(int[] array, int minIndex, int i) {
int tmp = array[i];
array[i] = array[minIndex];
array[minIndex] = tmp;
}
insertion sort
Time complexity:
Best case: O(N) when the data is completely ordered
Worst case: O(N^2) when the data is completely in reverse order
Space complexity: O(1)
Stability: Stable
The principle of insertion sort
- Make them key codes one by one starting from the first one on the left
- From left to right, insert the records to be sorted into the sorted sequence on the left one by one according to the size of their key values.
- Until all records are inserted, a new ordered sequence is obtained
public static void insertSort(int[] array){
for (int i = 1; i < array.length; i++) {
int tmp = array[i];
int j = i - 1;
for (; j >= 0 ; j--) {
//如果此处改为array[j] >= tmp就会变成不稳定排序
if (array[j] > tmp) {
array[j+1] = array[j];
}else{
break;
}
}
array[j+1] = tmp;
}
}
Hill sort
Time complexity:
approximately equal to: n^1.3 - n^1.5
Complexity: O(1)
Stability: unstableHill sorting is actually an optimization of insertion sorting
Fundamental:
- First divide the array into several groups according to the step size
- Insertion sort for each group
- Reduce the step size and repeat the above steps
public static void shellSort(int[] array){
int gap = array.length;
while (gap > 1) {
gap = gap / 2;
shell(array, gap);
}
}
private static void shell(int[] array, int gap) {
for (int i = gap; i < array.length; i++) {
int tmp = array[i];
int j = i-gap;
for (; j >= 0; j -= gap) {
if (array[j] > tmp) {
array[j+gap] = array[j];
}else {
break;
}
}
array[j+gap] = tmp;
}
}
merge sort
Time complexity: 0(N*logN)
Space complexity: O(n)
Stability: StableMerge sort is an effective sorting algorithm based on merge operations. This algorithm is a very typical application of the divide-and-conquer method. Merge the already ordered subsequences to obtain a completely ordered sequence; that is, first make each subsequence orderly, and then make the subsequence segments orderly.
public void mergerSort(int[] nums, int left, int right) {//right:数组长度减一
if (left >= right) {
return;
}
int mid = (left + right) / 2;
mergerSort(nums, left, mid);
mergerSort(nums, mid + 1, right);
merger(nums, left, mid, right);
}
private void merger(int[] nums, int left, int mid, int right) {
int[] tmp = new int[right-left+1];
int i = 0;
int l = left;
int r = mid + 1;
while (l <= mid && r <= right) {
if (nums[l] < nums[r]) {
tmp[i++] = nums[l++];
}else {
tmp[i++] = nums[r++];
}
}
while (l <= mid) {
tmp[i++] = nums[l++];
}
while (r <= right) {
tmp[i++] = nums[r++];
}
i = 0;
for (int j = 0; j < tmp.length; j++) {
nums[left++] = tmp[j];
}
}
Quick sort
Time complexity:
Best case: O(N*logN) full binary tree/complete binary tree
Worst case: O(N^2) single-branch tree
Space complexity:
Best case: O(logN) full binary tree/complete binary tree
Worst case: O(N) single-branch tree
Stability: unstableBasic principles of quick sort
- Take any element in the sequence of elements to be sorted as the base value
- Divide the set to be sorted into two subsequences according to this sorting code. All elements in the left subsequence are less than the reference value, and all elements in the right subsequence are greater than the reference value.
- Repeat this process for each subsequence until all elements are arranged in the corresponding position
There are the Hoare method, the digging method, and the front and rear pointer method.
Here we only introduce the Hoare method .
public static void quickSort(int[] array){
quick(array, 0, array.length-1);
}
private static void quick(int[] array, int left, int right) {
if (left >= right) {
return;
}
int Index = findSwap(array, left, right);
quick(array, left, Index-1);
quick(array, Index+1, right);
}
private static int findSwap(int[] array, int left, int right) {
int key = array[left];
int keyIndex = left;
while (left < right) {
//必须right先走
//如果是left先走,两个相遇的地方一定比key大
while (left < right && array[right] >= key) {
right--;
}
while (left < right && array[left] <= key) {
left++;
}
swap(array, right, left);
}
if (left == right) {
swap(array, keyIndex, left);
}
return left;
}
private static void swap(int[] array, int minIndex, int i) {
int tmp = array[i];
array[i] = array[minIndex];
array[minIndex] = tmp;
}
optimization
Use the three-number method to avoid the formation of branch books (try to reduce the height of the tree)
public int[] sortArray(int[] nums) {
//快速排序
quickSort(nums, 0, nums.length-1);
return nums;
}
private void quickSort(int[] nums, int left, int right) {
if (left >= right) {
return;
}
//三数取中法
swap(nums, left, threeNumMid(nums, left, right));
//也可以在这里加一个判断当左右之间的数据个数小于一定值然后调用插入排序
//因为在排序过程中数组会趋近于有序所以插入排序的效率会很快
int pivot = quick(nums, left, right);
quickSort(nums, left, pivot-1);
quickSort(nums, pivot+1, right);
}
private int threeNumMid(int[] nums, int left, int right) {
int mid = (left + right) / 2;
if (nums[left] > nums[right]) {
if (nums[mid] > nums[left]) {
return left;
}else if (nums[mid] < nums[right]) {
return right;
}else {
return mid;
}
}else {
if (nums[mid] < nums[left]) {
return left;
}else if (nums[mid] > nums[right]) {
return right;
}else {
return mid;
}
}
}
private int quick(int[] nums, int left, int right) {
int index = left;
int key = nums[left];
while (left < right) {
while (left < right && nums[right] >= key) {
right--;
}
while (left < right && nums[left] <= key) {
left++;
}
swap(nums, right, left);
}
swap(nums, index, left);
return left;
}
private void swap(int[] nums, int left, int right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
}
selection sort
Time complexity: O(n^2)
Space complexity: O(1)
Stability: unstable sortingBasic principles of selection sorting:
- Select the smallest (or largest) element from the data elements to be sorted each time from left to right.
- Place it at the beginning of the elements to be sorted and at the end of the ordered elements
- Repeat the above steps until all data elements to be sorted are arranged.
public static void selectSort(int[] array){
for (int i = 0; i < array.length; i++) {
int minIndex = i;
for (int j = i+1; j < array.length; j++) {
if (array[minIndex] > array[j]) {
minIndex = j;
}
}
swap(array, minIndex, i);
}
}
private static void swap(int[] array, int minIndex, int i) {
int tmp = array[i];
array[i] = array[minIndex];
array[minIndex] = tmp;
}