Summary of top ten sorting algorithms

Posted by anujgarg on Sat, 05 Mar 2022 15:10:00 +0100

Top ten sorting algorithms


Common sorting algorithms include bubble sort, selection sort, insertion sort, merge sort, quick sort, Hill sort, heap sort, count sort, bucket sort and cardinal sort

Bubble sorting

When adjacent elements are equal, they do not exchange positions, so bubble sorting is a stable sorting.

void bubbleSort(vector<int> & nums){
    // Cycle n-1 times
    for(int i = 0; i < nums.size() - 1; i++){ 
        // A maximum (small) value is found for each cycle, so the number of cycles per cycle decreases with the increase of i
        for(int j = 0; j < nums.size() - i - 1; j++){ 
            //In ascending order, change the large number to the back position
            if(nums[j] > nums[j + 1]){ 
                //Exchange two adjacent numbers
                swap(nums[j], nums[j + 1]); 
            }
        }
    }
}

Select sort

void selectSort(vector<int> & nums){
    for(int i = 0; i < nums.size() - 1; i++){ // Cycle n - 1
        int minIdx = i; //Loop to find the subscript of the minimum value, and then exchange the minimum value with the starting value
        for(int j = i; j < nums.size(); j++){
            if(nums[minIdx] > nums[j]){
                minIdx = j;
            }
        }
        swap(nums[i], nums[minIdx]);
    }
}

Insert sort

void insertSort(vector<int> & nums){
    for(int i = 1; i < nums.size(); i++){ // n - 1 cycle
      	int j;
        int num = nums[i];
      	//Find the first element num[j] less than or equal to the current number forward, and move the subsequent elements backward by one bit
        for(j = i - 1; j >= 0; j--){
            if(num < nums[j]){ //Move back
                nums[j + 1] = nums[j]; //Or swap (Num [J], Num [J + 1]);
            }else{
                break;
            }
        }
      	//Assign num to the next bit of num[j]
        nums[j + 1] = num;
    }
}

Shell Sort

Hill sort, also known as decreasing incremental sort algorithm, is a more efficient improved version of insertion sort. But Hill sorting is an unstable sorting algorithm.

Hill sort is an improved method based on the following two properties of insertion sort:

  • Insertion sorting is efficient when operating on almost ordered data, that is, it can achieve the efficiency of linear sorting;
  • However, insertion sorting is generally inefficient, because insertion sorting can only move data one bit at a time;

The basic idea of Hill sort is: first divide the whole record sequence to be sorted into several subsequences for direct insertion sort. When the records in the whole sequence are "basically orderly", then directly insert sort all records in turn.

void shell_sort(vector<int> & nums) {
    //Increment gap and gradually reduce the increment
    for (int gap = nums.size() / 2; gap > 0; gap /= 2) {
        //From the gap element, directly insert and sort the groups one by one
        for (int i = gap; i < nums.size(); i++) {
          	for(int j = i; j >= gap && nums[j] < nums[j - gap]; j -= gap){
              	swap(nums[j], nums[j - gap]);
            }
        }
    }
}

Merge sort

void merge(vector<int> & vec, int L1, int R1, int L2, int R2){
    vector<int> temp; //Auxiliary array
    int begin = L1;
    while(L1 <= R1 && L2 <= R2){
        if(vec[L1] < vec[L2]){ 
            temp.push_back(vec[L1++]);
        }else{
            temp.push_back(vec[L2++]);
        }
    }
    while(L1 <= R1){
        temp.push_back(vec[L1++]);
    }
    while(L2 <= R2){
        temp.push_back(vec[L2++]);
    }
  	vec.assign(temp.begin(), temp.end());
}

void mergeSort(vector<int> & vec, int left, int right){
    if(left < right){
        int mid = (left + right) / 2;
        mergeSort(vec, left, mid);
        mergeSort(vec, mid + 1, right);
        merge(vec, left, mid, mid + 1, right);
    }
}

Quick sort

Why is quick sort called quick sort?

https://blog.csdn.net/weixin_41445507/article/details/90255906

https://blog.csdn.net/linfeng24/article/details/38429055

int quick(vector<int> & vec, int left, int right){
    int temp = vec[left];
    while(left < right){
        //Find the first number on the left that is greater than or equal to temp
        while(left < right && vec[left] < temp){ 
            left += 1;
        }
        //Find the first number on the right that is less than or equal to temp
        while(left < right && vec[right] > temp){
            right -= 1;
        }
      	//Exchange two numbers
        swap(vec[left], vec[right]);
    }
    return left;
}

void quickSort(vector<int> & vec, int left, int right){
    if(left < right){
        int pos = quick(vec, left, right);
        quickSort(vec, left, pos - 1);
        quickSort(vec, pos + 1, right);
    }
}

Heap sort

Heap sort refers to a sort algorithm designed by using the data structure of heap. Heap is a structure similar to a complete binary tree, and satisfies the nature of heap at the same time: that is, the key value or index of a child node is always less than (or greater than) its parent node. Heap sort can be said to be a selective sort that uses the concept of heap to sort. There are two methods:

  1. Large top heap: the value of each node is greater than or equal to the value of its child nodes, which is used for ascending arrangement in heap sorting algorithm;
  2. Small top heap: the value of each node is less than or equal to the value of its child nodes, which is used for descending arrangement in heap sorting algorithm;

The average time complexity of heap sorting is Ο (nlogn).

// Build large top reactor
void buildMaxHeap(vector<int> & nums) {   
  	// Adjust the heap of each non leaf node
    for (int i = nums.size() / 2; i >= 0; i--) { 
        heapify(nums, i);
    }
}

// Heap adjustment, starting from the ith node
void heapify(vector<int> & nums, int i, int size) {    
    int left = 2 * i + 1; //Left child
    int right = 2 * i + 2; //Right child
    int largest = i;
		//Find the maximum of the left and right children
    if (left < size && nums[left] > nums[largest]) {
        largest = left;
    }

    if (right < size && nums[right] > nums[largest]) {
        largest = right;
    }
		
  	//Replace with parent node
    if (largest != i) {
        swap(nums[i], nums[largest]);
        heapify(nums, largest);
    }
}

void heapSort(vector<int> & nums) {
    buildMaxHeap(nums);
    for (int i = nums.size() - 1; i > 0; i--) {
      	// Put the top node last each time	
        swap(nums[0], nums[i]);
        heapify(nums, 0, i);
    }
    return nums;
}

Count sort

Counting sorting is not a comparative sorting, and the sorting speed is faster than any comparative sorting algorithm.

Since the length of the array used for counting depends on the range of data in the array to be sorted (equal to the difference between the maximum and minimum values of the array to be sorted plus 1), counting sorting requires a lot of time and memory for arrays with large data range.

void countingSort(vector<int> & nums) {
  	int maxValue = nums[0];
  	//Find maximum value
  	for(int i = 1; i < nums.size(); i++){
      	maxValue = max(maxValue, nums[i]);
    }
  
    vector<int> bucket(maxValue + 1, 0);

    for (int	 i = 0; i < maxValue + 1; i++) {
        bucket[nums[i]] += 1;
    }
		int idx = 0;
    for (int i = 0; i < maxValue + 1; i++) {
        while(bucket[i] > 0) {
            nums[idx++] = i;
            bucket[i] -= 1;
        }
    }
}

Bucket sorting

Bucket sorting is an upgraded version of counting sorting. It makes use of the mapping relationship of the function. The key to efficiency lies in the determination of the mapping function. In order to make bucket sorting more efficient, we need to do these two things:

  1. When there is enough extra space, try to increase the number of barrels
  2. The mapping function used can evenly distribute the input N data into K buckets

At the same time, for the sorting of elements in the bucket, it is very important to choose a comparative sorting algorithm for the performance.

  1. When is the fastest

When the input data can be evenly distributed to each bucket.

  1. When is the slowest

When the input data is allocated to the same bucket.

Cardinality sort

Radix sorting is a non comparative integer sorting algorithm

Cardinal sorting, counting sorting and bucket sorting all use the concept of bucket, but there are obvious differences in the use of bucket:

  • Cardinality sorting: allocate buckets according to each number of key value;
  • Counting and sorting: only one key value is stored in each bucket;
  • Bucket sorting: each bucket stores a certain range of values;

Topics: C++ Algorithm