The previous article has introduced several sorting algorithms, such as insert sort (direct insertion sort, binary insert sort, hill sort), swap sort (bubble sort, quick sort), select sort (Simple select sort, heap sort), 2-Path merge sort (can refer to the previous article: various internal sorting algorithm implementation), All of these sort algorithms have a common feature, which is based on comparisons.
This article will introduce three kinds of non comparison sorting algorithms: Count sort, cardinality sort, bucket sort. They will break through the lower bound of the comparison sort Ω (NLGN) and run at a linear time.
The time lower bound of the comparison sort algorithm
The so-called comparison order is to determine the relative order between elements by comparison.
"Theorem: For an input sequence containing n elements, any comparison sort algorithm in the worst case would need to do Ω (NLGN) comparisons." ”
That is, the comparison sort algorithm does not run faster than NLGN, which is the lower bound of the time based on the comparison sorting algorithm.
The decision Tree (Decision-tree) can prove this theorem, and the definition of decision tree and the process of proof are not discussed here. Readers can find their own information, here is recommended to take a look at MIT Open Class: An introduction to the MIT Open Class: Linear time sequencing.
According to the above theorem, we know that any comparison sort algorithm does not run faster than NLGN. So can we break through this limit? Of course, next we'll introduce three linear time sorting algorithms, which are not sorted by comparison, so lower bound Ω (NLGN) does not apply to them.
Second, counting sort (counting sort)
The basic idea of counting sort is to determine the number of elements less than x for each INPUT element x, so that x can be placed directly in the position of the final output array, for example:
The steps of the algorithm are roughly as follows:
①. Find the largest and smallest elements in an array to be sorted
②. Statistics the number of occurrences of an element in an array with the value of I, in the first item of the array C
③. Add to all counts (starting with the first element in C, and adding each item to the previous item)
④. Reverse-Populate the target array: Place each element I in the new array in subparagraph C (i), subtracting C (i) from each element by 1
C + + code is as follows:
/************************************************************************* > File Name : CountingSort.cpp > Author:songlee ************************************************************************/#i
Nclude<iostream> using namespace std;
* * Count Sort: A and B are rows and targets array, K is the maximum in array, Len is an array length/void Countingsort (int a[], int b[], int k, int len) {int c[k+1];
for (int i=0; i<k+1; ++i) c[i] = 0;
for (int i=0; i<len; ++i) c[a[i]] + = 1;
for (int i=1; i<k+1; ++i) c[i] = C[i] + c[i-1];
for (int i=len-1; i>=0;-I.) {B[C[A[I]]-1] = A[i];
C[a[i]]-= 1; }/* Output array/void print (int arr[], int len) {for (int i=0; i<len; ++i) cout << arr[i] << "
";
cout << Endl;
/* Test/INT main () {int origin[8] = {4,5,3,0,2,1,15,6};
int result[8];
Print (origin, 8);
Countingsort (Origin, result, 15, 8);
Print (result, 8);
return 0; }
When the input element is an integer between 0 and K, the time complexity is O (n+k), and the space complexity is O (n+k). When k is not very large and the sequence is more concentrated, counting is a very efficient sort algorithm. Counting sort is a stable sort algorithm.
Perhaps you will find that the counting sort seems to be a bit bend, for example, when we have just counted the number of c,c[i] that can represent the value of I in a, we scan C in a direct order, and we can find the result of the sort. This is true, but this method is no longer a sort of counting, but a bucket sort, and, exactly, a special case of bucket ordering.
Three, bucket sort (Bucket sort)
The idea of bucket ordering (Bucket sort) is to divide the array into a finite number of buckets. Each bucket is sorted individually (it is possible to use another sort algorithm). When the values in the array to be sorted are evenly distributed, the bucket sort can run at a linear time. Bucket Sort Process Animation Demo: Bucket sort, bucket sort schematic diagram as follows:
C + + code is as follows:
/************************************************************************* > File Name:BucketSort.cpp > Auth
Or:songlee ************************************************************************/#include <iostream>
using namespace Std;
///struct node {int value;
Node* Next;
};
/* Bucket sort/void Bucketsort (int a[], int max, int len) {node Bucket[len];
int count=0;
for (int i=0; i<len; ++i) {bucket[i].value = 0;
Bucket[i].next = NULL;
for (int i=0; i<len; ++i) {node *ist = new node ();
Ist->value = A[i];
Ist->next = NULL; int idx = a[i]*len/(max+1);
Computes the index if (bucket[idx].next = = NULL) {Bucket[idx].next = ist;
else/* Insert the corresponding position of the list in the order of size/{node *p = &bucket[idx];
Node *q = p->next;
while (q!=null && q->value <= a[i]) {p = q;
Q = p->next;
} ist->next = q; P->next = ist;
for (int i=0; i<len; ++i) {node *p = Bucket[i].next;
if (p = = NULL) continue;
while (p!= NULL) {a[count++] = p->value;
p = p->next; }}/* output array/void print (int a[], int len) {for (int i=0; i<len; ++i) cout << A[i] <<
";
cout << Endl;
/* Test/INT main () {int row[11] = {24,37,44,12,89,93,77,61,58,3,100};
Print (row, 11);
Bucketsort (Row, 235, 11);
Print (row, 11);
return 0;
}
Iv. Cardinal Order (radix sort)
The cardinality sort (radix sort) is a non-comparison sort algorithm that cuts integers by bits into different numbers, and then sorts each bit separately. Cardinality sorting can take the form of MSD (Most significant digital) or LSD (least significant), digital is sorted from the most significant bit, and LSD is sorted from the least significant bit.
Of course, we can sort by the MSD way, sort by the most significant bits, put the most significant bits in the same heap, and then sort the numbers recursively in each heap, then merge the results again with a valid bit. However, this can produce a lot of intermediate heaps. So, it's usually the LSD approach that the cardinal sort uses.
The basic idea of the LSD cardinal order implementation is to unify all the values to be compared (positive integers) to the same number of digits, preceded by a number of short digits of 0. Then, start at the lowest bit, and then sort it one at a time. This is done from the lowest bit to the highest order, and the sequence becomes an ordered series. It is important to note that the algorithm for sorting each digit must be stable, otherwise the result of the previous order will be canceled. Usually we use a counting sort or bucket sort as an auxiliary algorithm for cardinal ordering. Cardinal Sort Process Animation Demo: Radix sort
C + + implementations (using count sorting) are as follows:
/************************************************************************* > File Name:RadixSort.cpp > Autho
R:songlee ************************************************************************/#include <iostream>
using namespace Std;
Find the number int findit (int num, int n) {int power = 1) of integer num n bits;
for (int i = 0; i < n; i++) {power *= 10;
(num% power) * 10/POWER; }//Cardinality sort (use count sort as secondary) void Radixsort (int a[], int len, int k) {for (int i=1; i<=k; ++i) {int c[10] = { 0}; Count array int B[len];
Result array for (int j=0; j<len; ++j) {int d = findit (A[j], i);
C[D] + + 1;
for (int j=1; j<10; ++j) c[j] = C[j] + c[j-1];
for (int j=len-1; j>=0;--j) {int d = findit (A[j], i);
C[D]-= 1;
B[c[d]] = a[j];
///Copy the order in B to a for (int j=0; j<len; ++j) a[j] = B[j]; //output array void print (int a[], int Len) {for (int i=0; i<len; ++i) cout << a[i] << "";
cout << Endl;
//test int main () {int a[8] = {332, 653, 632, 5, 755, 433, 722, 48};
Print (A, 8);
Radixsort (A, 8, 3);
Print (A, 8);
return 0;
}
The time complexity of cardinality ordering is O (k n), where n is the number of sorted elements, and K is the number of digits. Note that this is not to say that this time complexity must be better than O (NLGN), because N may have a larger coefficient k.
In addition, the cardinality order can be sorted not only for integers, but also for records with multiple key fields. For example, the dates are sorted according to the year, month, and day of three keywords.