Article Directory
1. Algorithm classification
The ten common sorting algorithms can be divided into two broad categories:
- Compare class ordering:
- Determine the relative order of elements by comparison
- Because its time complexity cannot be broken through
O(nlogn)
, it is also called nonlinear time comparison sorting.
- Non-comparative sorting:
- Relative ordering of elements is not determined by comparison
- It can break through the time lower bound of comparison-based sorting and run in linear time, so it is also called linear-time non-comparative sorting.
2. Overview of classic sorting algorithms
The ten classic algorithms are:
-
bubble sort
- Bubble Sort (Bubble Sort) is an exchange -based sort
- Each time you traverse the elements that need to be sorted, compare the size of the adjacent two elements in turn . If the previous element is greater than the latter element, exchange the two to ensure that the last number must be the largest (assuming that it is sorted from small to large
- That is, the last element has been sorted, and the next round only needs to ensure the order of the first n-1 elements .
Process demonstration: array to be sorted {5, 4, 7, 1, 6, 2}, sorted in ascending order
Algorithm steps:
- Compare adjacent elements . If the first is greater than the second, swap them both;
- Do the same for each pair of adjacent elements , from the first pair at the beginning to the last pair at the end, so the element at the end should be the largest number;
- Repeat the above steps for all elements except the last one;
- Repeat steps 1~3 until sorting is complete.
- selection sort
- The bubble sort mentioned above is to determine the last element in each round of comparison, and the middle process is constantly exchanged.
- The selection sort is to select the smallest element among the remaining elements each time , and exchange it with the element at the current index position until all the index positions are selected.
[Algorithm steps] n
The direct selection and sorting of a record can n-1
obtain an ordered result through direct selection and sorting. The specific algorithm is described as follows:
- Initial state: the unordered area is
R[1..n]
, the ordered area is empty; - At the beginning of the first
i
sorting ( ), the current ordered area and unordered area are andi=1,2,3…n-1
respectively .R[1..i-1]
R(i..n)
- This sorting process selects the record with the smallest key from the current unordered area , and exchanges it with the first record R
R[k]
in the unordered area1
- Make
R[1..i]
and respectively become a new ordered area withR[i+1..n)
the number of records increased by 1 and a new disordered area with the number of records decreased by 1 ;
- This sorting process selects the record with the smallest key from the current unordered area , and exchanges it with the first record R
n-1
At the end of the pass, the array is sorted.
- insertion sort
- Selection sort is to select the smallest one each time and put it behind the array that has been arranged
- The insertion sort is to select an element in turn and insert it into the middle of the previously sorted array to ensure that it is in the correct position.
- Of course, this requires constant movement of the sorted array .
[Algorithm steps] Generally speaking, insertion sorting is implemented on arrays using in-place. The specific algorithm is described as follows:
- Starting from the first element, the element can be considered sorted;
- Take out the next element and scan from back to front in the sorted element sequence;
- If the element (sorted) is larger than the new element, move the element to the next position;
- Repeat step 3 until you find the position where the sorted element is less than or equal to the new element;
- After inserting a new element at that position;
- Repeat steps 2~5.
- Hill sort
- Shell's Sort, also known as " Diminishing Increment Sort", is a more efficient and improved version of insertion sort.
- The pain point of insertion sort is that no matter whether it is mostly ordered or not, elements will be compared. If the minimum number is at the end of the array, it will be more laborious to move it to the head of the array.
- Hill sorting is to use jump grouping in the array, group according to a certain incremental gap, divide it into several groups, and perform insertion sorting on each group .
- Then gradually reduce the incremental gap
- Insertion sort is performed on each group, and the process is repeated until the increment is 1.
[Algorithm steps] First divide the entire record sequence to be sorted into several subsequences for direct insertion sorting . The specific algorithm description:
- Choose a sequence of increments
t1,t2,…,tk
whereti > tj
;tk = 1
- According to the number of incremental sequences
k
, sort the sequencek
times; - For each sorting, according to the corresponding increment
ti
, the column to be sorted is divided into severalm
subsequences of length , and direct insertion sorting is performed on each subtable.- Only when the increment factor is
1
, the entire sequence is treated as a table, and the length of the table is the length of the entire sequence.
- Only when the increment factor is
- quick sort
- Quick sort is more interesting. Select a number in the array as the reference number, sort in one pass, and divide the array into two parts
- Some of them are less than/equal to the benchmark
- The other part is greater than/equal to the benchmark number.
- Then continue to sort the left and right parts of the benchmark number until the array is in order. This embodies the idea of divide and conquer , which is also applied to the strategy of digging holes and filling numbers.
- Quick sort is more interesting. Select a number in the array as the reference number, sort in one pass, and divide the array into two parts
[Algorithm steps] Quick sort uses divide and conquer method to divide a string (list) into two sub-strings (sub-lists). The specific algorithm is described as follows:
- Pick an element from the sequence, called the "pivot" ;
- Reorder the sequence, all elements smaller than the reference value are placed in front of the reference value , and all elements larger than the reference value are placed behind the reference value (the same number can go to either side).
- After this partition exits, the benchmark is in the middle of the sequence . This is called a partition operation ;
- Recursively sort subarrays with elements less than the base value and subarrays with elements greater than the base value .
- merge sort
- The previous quick sort embodies the idea of divide and conquer, but it is not typical
- Merge sort is a very typical divide and conquer strategy . The general idea of merging is to split the array first, then split ...
- It is divided into one element, and then merged and sorted in pairs to achieve partial order, and merged continuously until the array is all combined again.
Algorithm steps
n
splits the input sequence of length into twon/2
subsequences of length ;- Use merge sort for the two subsequences respectively ;
- Merges two sorted subsequences into a final sorted sequence.
- bucket sort
- Bucket sorting refers to using multiple buckets to store elements, and each bucket has a storage range
- First put the elements into each bucket according to the range, and each bucket is a sub-array, then sort each sub-array , and finally merge the sub-arrays to become the final ordered array.
- This is actually very similar to counting sort, except that counting sort has only one element in each bucket, and the value stored in the bucket is the number of occurrences of the element.
Algorithm steps
- Set a quantitative array as an empty bucket ;
- Traverse the input data and put the data one by one into the corresponding bucket ;
- Sort each bucket that is not empty ;
- Concatenate sorted data from non-empty buckets .
- heap sort
- Heap sorting is a sorting algorithm designed using a large top heap or a small top heap . It is a selection sort.
- A heap is a complete binary tree :
- Big top heap: The value of each node is greater than or equal to the value of its left and right child nodes .
- Small top heap: the value of each node is less than or equal to the value of its left and right child nodes .
Algorithm steps:
- Build the initial sequence of keywords
(R1,R2….Rn)
to be sorted into a large top heap , which is the initial unordered area; - Exchange the top element of the heap
R[1]
with the last elementR[n]
, and get a new unordered area(R1,R2,……Rn-1)
and a new ordered area at this time(Rn)
, and satisfyR[1,2…n-1]<=R[n]
; - Since the new heap top after the exchange
R[1]
may violate the nature of the heap, it is necessary to adjust the current unordered area(R1,R2,……Rn-1)
to a new heap , and thenR[1]
exchange the last element with the unordered area again to obtain a new unordered area(R1,R2….Rn-2)
and a new ordered area(Rn-1,Rn)
. - Repeat this process until the number of elements in the sorted area is
n-1
, then the entire sorting process is complete.
- counting sort
- Counting sort, not based on comparison, but on count
- It is more suitable for cases where the element values are similar and are integers
Algorithm steps
- Find the largest and smallest elements in the array to be sorted ;
- Count the number of
i
occurrences of elements with each value in the array , and store them in the first item of array C ;i
- Accumulate all counts (starting
C
from the first element, each item is added to the previous item); - Fill the target array in reverse: put each element i in the item of the new array , and subtract 1
C(i)
for each element placed .C(i)
- radix sort
- Cardinality sorting is special in that it can only be used for integer (natural number) sorting , and it is not based on comparison .
- The principle is to divide the integer into different numbers according to the digits, and sort them step by step according to the value of each digit .
- What is the high bit, such as 81, 1 is the low bit, and 8 is the high bit.
- Divided into high-order priority and low-order priority , comparing the high-order first is the high-order priority, and comparing the low-order first is the low-order priority.
Algorithm steps:
- Obtain the maximum number in the array and obtain the number of digits ;
arr
For the original array, each bit is taken from the lowest bit to formradix
an array;radix
Counting and sorting ( using counting sorting is suitable for small range numbers);
3. Algorithm complexity
Common sorting algorithm complexity
Related concepts
- Stable : If a is originally in front of b, and a=b, a is still in front of b after sorting .
- Unstable : If a is originally in front of b, and a=b, a may appear behind b after sorting .
- Time complexity: The total number of operations on sorted data . It reflects the regularity of the number of operations when n changes.
- Space complexity: refers to the measurement of the storage space required by the algorithm when it is executed in the computer , and it is also a function of the data size n
4. Code implementation
- Bubble Sort
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
// 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
- Selection Sort
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
// 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
- Insertion Sort
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
- Shell sort (Shell Sort)
function shellSort(arr) {
var len = arr.length;
for (var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
// 注意:这里和动图演示的不一样,动图是分组执行,实际操作是多个分组交替执行
for (var i = gap; i < len; i++) {
var j = i;
var current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
return arr;
}
- Merge Sort
function mergeSort(arr) {
var len = arr.length;
if (len < 2) {
return arr;
}
var middle = Math.floor(len / 2),
left = arr.slice(0, middle),
right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
var result = [];
while (left.length>0 && right.length>0) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
- Quick sort (Quick Sort)
function quickSort(arr, left, right) {
var len = arr.length,
partitionIndex,
left = typeof left != 'number' ? 0 : left,
right = typeof right != 'number' ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex-1);
quickSort(arr, partitionIndex+1, right);
}
return arr;
}
function partition(arr, left ,right) {
// 分区操作
var pivot = left, // 设定基准值(pivot)
index = pivot + 1;
for (var i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index-1;
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
- Heap Sort
var len; // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量
function buildMaxHeap(arr) {
// 建立大顶堆
len = arr.length;
for (var i = Math.floor(len/2); i >= 0; i--) {
heapify(arr, i);
}
}
function heapify(arr, i) {
// 堆调整
var left = 2 * i + 1,
right = 2 * i + 2,
largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
heapify(arr, largest);
}
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function heapSort(arr) {
buildMaxHeap(arr);
for (var i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0);
}
return arr;
}
- Counting Sort
function countingSort(arr, maxValue) {
var bucket = new Array(maxValue + 1),
sortedIndex = 0;
arrLen = arr.length,
bucketLen = maxValue + 1;
for (var i = 0; i < arrLen; i++) {
if (!bucket[arr[i]]) {
bucket[arr[i]] = 0;
}
bucket[arr[i]]++;
}
for (var j = 0; j < bucketLen; j++) {
while(bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
- Bucket Sort
function bucketSort(arr, bucketSize) {
if (arr.length === 0) {
return arr;
}
var i;
var minValue = arr[0];
var maxValue = arr[0];
for (i = 1; i < arr.length; i++) {
if (arr[i] < minValue) {
minValue = arr[i]; // 输入数据的最小值
} else if (arr[i] > maxValue) {
maxValue = arr[i]; // 输入数据的最大值
}
}
// 桶的初始化
var DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5
bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
var buckets = new Array(bucketCount);
for (i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
// 利用映射函数将数据分配到各个桶中
for (i = 0; i < arr.length; i++) {
buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
}
arr.length = 0;
for (i = 0; i < buckets.length; i++) {
insertionSort(buckets[i]); // 对每个桶进行排序,这里使用了插入排序
for (var j = 0; j < buckets[i].length; j++) {
arr.push(buckets[i][j]);
}
}
return arr;
}
- Radix Sort (Radix Sort)
var counter = [];
function radixSort(arr, maxDigit) {
var mod = 10;
var dev = 1;
for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for(var j = 0; j < arr.length; j++) {
var bucket = parseInt((arr[j] % mod) / dev);
if(counter[bucket]==null) {
counter[bucket] = [];
}
counter[bucket].push(arr[j]);
}
var pos = 0;
for(var j = 0; j < counter.length; j++) {
var value = null;
if(counter[j]!=null) {
while ((value = counter[j].shift()) != null) {
arr[pos++] = value;
}
}
}
}
return arr;
}