Data Structures and Algorithms 17. Sorting Algorithms

First, the exchange order

1. Bubble sort

        The Bubble Sort algorithm is the simplest and most basic of all sorting algorithms. The idea of ​​the bubble sort algorithm is to exchange sorting, and achieve the purpose of sorting through the exchange of adjacent data.

        Average speed is O(n2), worst case speed is O(n2);

        The bubble sort algorithm implements sorting through multiple comparisons and exchanges. The sorting process is as follows:

        (1) For each data in the array, compare the size of two adjacent elements in turn.

        (2) If the previous data is greater than the latter data, exchange the two data. After the first round of multiple comparisons and sorting, the smallest data can be sorted.

        (3) Use the same method to compare the remaining data one by one, and finally arrange the data of the array in order from small to large.

public static <T extends Comparable<T>> T[] bubble_sort(T[] array) {
    for (int i = 1, size = array.length; i < size; ++i) {
        boolean swapped = false;
        for (int j = 0; j < size - i; ++j) {
            //判断大小
            if (greater(array[j], array[j + 1])) {
                //交换位置
                swap(array, j, j + 1);
                swapped = true;
            }
        }
        if (!swapped) {
            break;
        }
    }
    return array;
}

2. Quick sort

        The Quick Sort algorithm is similar to the Bubble Sort algorithm and is based on the idea of ​​​​exchange sorting. The quick sort algorithm improves the bubble sort algorithm, so that it has higher execution efficiency. Quicksort is a divide and conquer algorithm. It selects an element as an axis and partitions the given array around the selected axis. There are many different versions of quickSort that select axes in different ways. 

        Average speed is O(nlogn), worst case speed is O(n2)

        The quick sort algorithm implements sorting through multiple comparisons and exchanges. The sorting process is as follows:

        (1) First set a demarcation value, and divide the array into left and right parts by this demarcation value.

        (2) Put the data greater than or equal to the cutoff value to the right of the array, and the data less than the cutoff value to the left of the array. At this time, each element in the left part is less than or equal to the cutoff value, and each element in the right part is greater than or equal to the cutoff value.

        (3) Then, the left and right data can be sorted independently. For the array data on the left, another demarcation value can be taken, the part of the data can be divided into left and right parts, and the smaller value is placed on the left and the larger value is placed on the right. The array data on the right can also be processed similarly.

        (4) Repeating the above process, it can be seen that this is a recursive definition. After the left part is sorted recursively, the right part is sorted recursively. When the sorting of the data in the left and right parts is completed, the sorting of the entire array is completed.

package com.algorithm.demo.algorithms;

import static com.algorithm.demo.algorithms.SortUtils.*;

public class QuickSortAlgorithm {

    /**
     * 对外的方法
     *
     * @param array 要排序的数组,按升序对数组进行排序
     */
    public static <T extends Comparable<T>> T[] sort(T[] array) {
        doSort(array, 0, array.length - 1);
        return array;
    }

    /**
     * 排序方法
     *
     * @param left The first index of an array
     * @param right The last index of an array
     * @param array The array to be sorted
     */
    private static <T extends Comparable<T>> void doSort(T[] array, int left, int right) {
        if (left < right) {
            int pivot = randomPartition(array, left, right);
            doSort(array, left, pivot - 1);
            doSort(array, pivot, right);
        }
    }

    /**
     * 随机化数组以避免基本有序的序列
     * Ramdomize the array to avoid the basically ordered sequences
     *
     * @param array The array to be sorted
     * @param left The first index of an array
     * @param right The last index of an array
     * @return the partition index of the array
     */
    private static <T extends Comparable<T>> int randomPartition(T[] array, int left, int right) {
        int randomIndex = left + (int) (Math.random() * (right - left + 1));
        swap(array, randomIndex, right);
        return partition(array, left, right);
    }

    /**
     * 此方法查找数组的分区索引
     * This method finds the partition index for an array
     *
     * @param array The array to be sorted
     * @param left The first index of an array
     * @param right The last index of an array Finds the partition index of an
     * array
     */
    private static <T extends Comparable<T>> int partition(T[] array, int left, int right) {
        int mid = (left + right) >>> 1;
        T pivot = array[mid];

        while (left <= right) {
            while (less(array[left], pivot)) {
                ++left;
            }
            while (less(pivot, array[right])) {
                --right;
            }
            if (left <= right) {
                swap(array, left, right);
                ++left;
                --right;
            }
        }
        return left;
    }
}

 Second, the selection sort

        The Selection Sort algorithm is also a relatively simple sorting algorithm, and its idea is more intuitive. The selection sort algorithm selects the minimum value in each step to rearrange, so as to achieve the purpose of sorting.

        Average speed O(n2), worst case speed O(n2)

        The selection sort algorithm realizes sorting by selection and exchange, and the sorting process is as follows:

        (1) First select the smallest 1 data from the original array, and exchange it with the data at the 1st position.

        (2) Then select the next smallest data from the remaining n-1 data, and exchange it with the data in the second position.

        (3) Then repeat the above process until the last two data are exchanged. At this point, the sorting of the original array from small to large is completed.

         When the insertion sort algorithm sorts n data, no matter whether the original data is in order or not, it needs to perform an intermediate sorting of n-1 steps. The idea of ​​this sorting method is simple and intuitive, and when the data has a certain order, the sorting efficiency is better. However, if the data is irregular, a large amount of data needs to be moved, and the sorting efficiency is not high.

public static <T extends Comparable<T>> T[] selection_sort(T[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[minIndex].compareTo(arr[j]) > 0) {
                minIndex = j;
            }
        }
        if (minIndex != i) {
            T temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
    return arr;
}

3. Insertion sort

        The Insertion Sort algorithm completes the sorting work by inserting the unsorted data into the appropriate position one by one. The idea of ​​insertion sort algorithm is relatively simple and has many applications.

        Average speed is O(n2), worst case speed is O(n2)

        The insertion sort algorithm implements sorting by comparison and insertion. The sorting process is as follows:

        (1) First, sort the first two data of the array from small to large.

        (2) Then compare the third data with the sorted two data, and insert the third data into the appropriate position.

        (3) Then, insert the 4th data into the sorted first 3 data.

        (4) Repeat the above process until the last data is inserted into the appropriate position. Finally, the sorting of the original array from small to large is completed.

/**
 * 插入排序
 * @param array
 * @return
 */
public static <T extends Comparable<T>> T[] insertion_sort(T[] array) {
    for (int i = 1; i < array.length; i++) {
        T insertValue = array[i];
        int j;
        for (j = i - 1; j >= 0 && less(insertValue, array[j]); j--) {
            array[j + 1] = array[j];
        }
        if (j != i - 1) {
            array[j + 1] = insertValue;
        }
    }
    return array;
}

Fourth, merge sort

        The Merge Sort algorithm combines multiple ordered data tables into one ordered data table. If there are only two ordered tables involved in the merge, it is called a two-way merge. For an original sequence to be sorted, it can often be attributed to the multi-way merge sort by the method of division. The following takes two-way merge as an example to introduce the merge sort algorithm.

        The average speed is O(nlogn), and the worst-case speed is O(nlogn).

        The basic idea of ​​merging and sorting an original data sequence to be sorted is to first regard the data sequence to be sorted containing n nodes as consisting of n ordered sub-lists of length 1, and merge them in turn to obtain Several ordered sublists of length 2; then, these sublists are merged in pairs to obtain several ordered sublists of length 4..., repeat the above process until the length of the final sublist is n, thus Complete the sorting process.

 

class MergeSort
{

	void merge(int arr[], int l, int m, int r)
	{
		// Find sizes of two subarrays to be merged
		int n1 = m - l + 1;
		int n2 = r - m;

		/* Create temp arrays */
		int L[] = new int[n1];
		int R[] = new int[n2];

		/*Copy data to temp arrays*/
		for (int i = 0; i < n1; ++i)
			L[i] = arr[l + i];
		for (int j = 0; j < n2; ++j)
			R[j] = arr[m + 1 + j];

		/* Merge the temp arrays */

		// Initial indexes of first and second subarrays
		int i = 0, j = 0;

		// Initial index of merged subarray array
		int k = l;
		while (i < n1 && j < n2) {
			if (L[i] <= R[j]) {
				arr[k] = L[i];
				i++;
			}
			else {
				arr[k] = R[j];
				j++;
			}
			k++;
		}

		/* Copy remaining elements of L[] if any */
		while (i < n1) {
			arr[k] = L[i];
			i++;
			k++;
		}

		/* Copy remaining elements of R[] if any */
		while (j < n2) {
			arr[k] = R[j];
			j++;
			k++;
		}
	}

	// Main function that sorts arr[l..r] using
	// merge()
	void sort(int arr[], int l, int r)
	{
		if (l < r) {
			// Find the middle point
			int m =l+ (r-l)/2;

			// Sort first and second halves
			sort(arr, l, m);
			sort(arr, m + 1, r);

			// Merge the sorted halves
			merge(arr, l, m, r);
		}
	}

	/* A utility function to print array of size n */
	static void printArray(int arr[])
	{
		int n = arr.length;
		for (int i = 0; i < n; ++i)
			System.out.print(arr[i] + " ");
		System.out.println();
	}

	// Driver code
	public static void main(String args[])
	{
		int arr[] = { 12, 11, 13, 5, 6, 7 };

		System.out.println("Given Array");
		printArray(arr);

		MergeSort ob = new MergeSort();
		ob.sort(arr, 0, arr.length - 1);

		System.out.println("\nSorted array");
		printArray(arr);
	}
}
/* This code is contributed by Rajat Mishra */

 5. Shell sorting

        Strictly speaking, the Shell sorting algorithm is based on the idea of ​​insertion sorting, which is also known as Hill sorting or shrinking incremental sorting. The sorting process of the Shell sorting algorithm is as follows:

        (1) Divide an array with n elements into n/2 number sequences, the 1st data and the n/2+1th data are a pair, ...

        (2) A loop makes each sequence pair in order.

        (3) Then, change to n/4 sequences and sort again.

        (4) Repeat the above process continuously, and as the sequence decreases and finally becomes one, the entire sorting is completed.

        The average speed is O(n3/2), and the worst-case speed is O(n2).

class ShellSort
{
    //打印
    static void printArray(int arr[])
    {
        int n = arr.length;
        for (int i=0; i<n; ++i)
            System.out.print(arr[i] + " ");
        System.out.println();
    }
    
    //排序方法
    int sort(int arr[])
    {
        int n = arr.length;
 
        // 从大差距开始,然后缩小差距
        for (int gap = n/2; gap > 0; gap /= 2)
        {
            
            for (int i = gap; i < n; i += 1)
            {
                int temp = arr[i];
                int j;
                for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
                    arr[j] = arr[j - gap];
 
                arr[j] = temp;
            }
        }
        return 0;
    }
 

    public static void main(String args[])
    {
        int arr[] = {12, 34, 54, 2, 3};
        System.out.println("Array before sorting");
        printArray(arr);
 
        ShellSort ob = new ShellSort();
        ob.sort(arr);
 
        System.out.println("Array after sorting");
        printArray(arr);
    }
}

6. Bucket sorting

        Bucket sort is a sorting algorithm that divides elements into groups called buckets. Elements in bucket sort are first uniformly divided into groups called buckets, and then they are sorted by any other sorting algorithm. After that, the elements are collected in a sorted manner.

        The basic process of performing bucket sort is as follows:

        First, divide the range into a fixed number of buckets.
        Then, throw each element into the corresponding bucket.
        After that, each bucket is sorted individually by applying a sorting algorithm.
        Finally, join all sorted buckets.

        The best and average case complexity of bucket sort is O(n + k) and the worst case complexity of bucket sort is O(n 2 )

import java.util.*;
import java.util.Collections;

class BucketSort {

	// Function to sort arr[] of size n
	// using bucket sort
	static void bucketSort(float arr[], int n)
	{
		if (n <= 0)
			return;

		// 1) Create n empty buckets
		@SuppressWarnings("unchecked")
		Vector<Float>[] buckets = new Vector[n];

		for (int i = 0; i < n; i++) {
			buckets[i] = new Vector<Float>();
		}

		// 2) Put array elements in different buckets
		for (int i = 0; i < n; i++) {
			float idx = arr[i] * n;
			buckets[(int)idx].add(arr[i]);
		}

		// 3) Sort individual buckets
		for (int i = 0; i < n; i++) {
			Collections.sort(buckets[i]);
		}

		// 4) Concatenate all buckets into arr[]
		int index = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < buckets[i].size(); j++) {
				arr[index++] = buckets[i].get(j);
			}
		}
	}

	// Driver code
	public static void main(String args[])
	{
		float arr[] = { (float)0.897, (float)0.565,
						(float)0.656, (float)0.1234,
						(float)0.665, (float)0.3434 };

		int n = arr.length;
		bucketSort(arr, n);

		System.out.println("Sorted array is ");
		for (float el : arr) {
			System.out.print(el + " ");
		}
	}
}

Seven, multi-way merge sort

        For some large files, due to the limited memory of the computer, it is often impossible to directly read them into the memory for sorting. At this time, the multi-way merge sort method can be used to divide the file into several small parts that can be read into the memory, and then read and sorted separately. After multiple processing, the sorting of large files can be completed.

Guess you like

Origin blog.csdn.net/bashendixie5/article/details/123283951