经典超详细排序算法(20种)Java语言

排序:快速排序法、堆排序法、冒泡排序法、归并排序法以及插入排序法还有希尔排序法、选择排序法、基数排序法,桶排序法、冒泡改进排序法、快速改进排序法、O(NlogN)排序法,基数桶排序法、外部排序法、内部排序法、交错排序法还有一些较少被使用的排序算法,如希尔伯特曲线排序、梳排序、块排序、序位排序。

1.快速排序:

Java实现快速排序的代码(来源:https://www.geeksforgeeks.org/quick-sort/ ):

// Java implementation of QuickSort

import java.io.*;

  

class GFG {

  

    // A utility function to swap two elements

    static void swap(int[] arr, int i, int j)

    {

        int temp = arr[i];

        arr[i] = arr[j];

        arr[j] = temp;

    }

  

    /* This function takes last element as pivot, places

       the pivot element at its correct position in sorted

       array, and places all smaller (smaller than pivot)

       to left of pivot and all greater elements to right

       of pivot */

    static int partition(int[] arr, int low, int high)

    {

  

        // pivot

        int pivot = arr[high];

  

        // Index of smaller element and

        // indicates the right position

        // of pivot found so far

        int i = (low - 1);

  

        for (int j = low; j <= high - 1; j++) {

  

            // If current element is smaller

            // than the pivot

            if (arr[j] < pivot) {

  

                // Increment index of

                // smaller element

                i++;

                swap(arr, i, j);

            }

        }

        swap(arr, i + 1, high);

        return (i + 1);

    }

  

    /* The main function that implements QuickSort

              arr[] --> Array to be sorted,

              low --> Starting index,

              high --> Ending index

     */

    static void quickSort(int[] arr, int low, int high)

    {

        if (low < high) {

  

            // pi is partitioning index, arr[p]

            // is now at right place

            int pi = partition(arr, low, high);

  

            // Separately sort elements before

            // partition and after partition

            quickSort(arr, low, pi - 1);

            quickSort(arr, pi + 1, high);

        }

    }

  

    // Function to print an array

    static void printArray(int[] arr, int size)

    {

        for (int i = 0; i < size; i++)

            System.out.print(arr[i] + " ");

  

        System.out.println();

    }

  

    // Driver Code

    public static void main(String[] args)

    {

        int[] arr = { 10, 7, 8, 9, 1, 5 };

        int n = arr.length;

  

        quickSort(arr, 0, n - 1);

        System.out.println("Sorted array: ");

        printArray(arr, n);

    }

}

  

// This code is contributed by Ayush Choudhary

 

2.冒泡排序

 

下面是用Java实现冒泡排序的算法:

    /* 
    *  冒泡排序方法  
    *  for循环外层从0开始到数组最后一个元素-1,  内层for循环从0开始到i前面的元素 
    *  比较arr[j]和arr[j+1]的大小,如果arr[j]大于arr[j+1],则交换位置 
    */
public static void bubbleSort(int[] arr) {   
    int temp;   
    for (int i = 0; i < arr.length - 1; i++) {   
        for (int j = 0; j < arr.length - 1 - i; j++) {   
            if (arr[j] > arr[j + 1]) { // 交换变量位置 
                temp = arr[j];   
                arr[j] = arr[j + 1];   
                arr[j + 1] = temp;   
            }   
        }   
    }   
}

当然,冒泡排序法,当循环到其中一圈的时候,假如已经有序了,就没有必要再向后进行循环,详细的方法看10.冒泡改进排序。

3.堆排序

下面是一个用Java实现堆排序的算法:

/**
* 堆排序
*
* @param arr
* 待排序列
*/
public static void heapSort(int[] arr) {
// build heap
for (int i = arr.length / 2 - 1; i >= 0; i--) {
heapAdjust(arr, i, arr.length);
}

for (int i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
heapAdjust(arr, 0, i);
}
}

/**
* 调整堆
*
* @param arr
* 待排序列
* @param parent
* 父节点
* @param length
* 待排序列尾元素索引
*/
public static void heapAdjust(int[] arr, int parent, int length) {
int temp = arr[parent]; // temp保存当前父节点
int child = 2 * parent + 1; // 先获得左孩子

while (child < length) {
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (child + 1 < length && arr[child] < arr[child + 1]) {
child++;
}

// 如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= arr[child])
break;

// 把孩子结点的值赋给父结点
arr[parent] = arr[child];

// 选取孩子结点的左孩子结点,继续向下筛选
parent = child;
child = 2 * child + 1;
}
arr[parent] = temp;
}

/**
* 交换元素位置
*
* @param arr
* 待交换列表
* @param a
* 元素下标
* @param b
* 元素下标
*/
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}

4.归并排序

下面是一个用Java实现归并排序的算法,并带有中文注释:

    /**     
     * 归并排序     
     *     
     * @param arr     
     *            待排序列     
     */      
public static void mergeSort(int[] arr) {     
    mergeSortC(arr, 0, arr.length - 1);     
}  
  
/**     
 * 递归调用函数     
 *     
 * @param arr     
 *            待排序列     
 * @param left     
 *            左边界 
 * @param right     
 *            右边界 
 */    
public static void mergeSortC(int[] arr, int left, int right) {  
    if (left == right)  
        return;     
    int mid = (left + right) / 2;  
    // 左边数组排序  
    mergeSortC(arr, left, mid);     
    // 右边数组排序  
    mergeSortC(arr, mid + 1, right);     
    // 合并两个有序数组  
    merge(arr, left, mid, right);     
}  
  
/**     
 * 合并两个有序数组     
 *     
 * @param arr     
 *            排序数组 
 * @param left     
 *            左边界 
 * @param mid     
 *            中间 
 * @param right     
 *            右边界 
 */      
public static void merge(int[] arr, int left, int mid, int right) {     
    int[] temp = new int[right - left + 1];  
    int i = left;     
    int j = mid + 1;     
    int k = 0;  
  
    // 把较小的数先移到新数组中  
    while (i <= mid && j <= right) {     
        if (arr[i] <= arr[j]) {     
            temp[k++] = arr[i++];     
        } else {     
            temp[k++] = arr[j++];     
        }     
    }     
  
    // 把左边剩余的数移入数组  
    while (i <= mid) {     
        temp[k++] = arr[i++];     
    }  
  
    // 把右边剩余的数移入数组  
    while (j <= right) {     
        temp[k++] = arr[j++];     
    }  
  
    // 把新数组中的数覆盖arr数组  
    for (int k2 = 0; k2 < temp.length; k2++) {     
        arr[k2 + left] = temp[k2];     
    }     
}

5.插入排序

下面是一个使用Java实现插入排序算法的语句,并带有中文注释:

/**     
 * 插入排序     
 *     
 * @param arr     
 *            待排序列     
 */ 
public static void insertionSort(int[] arr) {  
    for (int i = 1; i < arr.length; i++) {     
        int j = i - 1;  
        int temp = arr[i];     
        // 寻找插入位置并移动数据  
        while (j >= 0 && arr[j] > temp) {     
            arr[j + 1] = arr[j];     
            j--;     
        }  
        arr[j + 1] = temp;     
    }     
}

6.希尔排序

下面是一个使用Java实现希尔排序算法的语句,并带有详细注释:

/**     
 * 希尔排序     
 *     
 * @param array     
 *            待排序列     
 */     
public static void shellSort(int[] array) {   
    int increment = array.length / 2;  
    while (increment >= 1){     
        for (int i = increment; i < array.length; i++) {     
            int j = i - increment;     
            int temp = array[i];     
            // 寻找插入位置并移动数据     
            while (j >= 0 && array[j] > temp) {     
                array[j + increment] = array[j];     
                j -= increment;     
            }     
            array[j + increment] = temp;   
        }     
        // 设置新的增量     
        increment /= 2;     
    }     
}

7.基数排序

下面是一个使用Java实现基数排序算法的语句,并带有中文注释:

 

基数排序的代码实现如下:

// 获取数组中最大元素的位数 
int getMaxDigit(int[] array) { 
    int maxValue = array[0]; 
    for (int i = 1; i < array.length; i++) { 
        if (maxValue < array[i]) { 
            maxValue = array[i]; 
        } 
    } 
    return getNumLenght(maxValue); 

// 基数排序实现 
public void radixSort(int[] array, int radix) { 
    // 获取数组中最大元素的位数 
    int maxDigit = getMaxDigit(array); 
    
    // 申请桶 
    int[][] buckets = new int[radix][array.length]; 
    // 申请计数器,记录每个桶中实际存放了多少个数据 
    int[] counters = new int[radix]; 

    // 从低位到高位开始进行排序 
    for (int d = 0; d < maxDigit; d++) { 
        // 将数据放入桶中 
        for (int i = 0; i < array.length; i++) { 
            int bucketIndex = getDigit(array[i], d); 
            buckets[bucketIndex][counters[bucketIndex]] = array[i]; 
            counters[bucketIndex]++; 
        } 

        // 将桶中数据放回原始数组 
        int index = 0; 
        for (int i = 0; i < radix; i++) { 
            for (int j = 0; j < counters[i]; j++) { 
                array[index] = buckets[i][j]; 
                index++; 
            } 
            // 重置计数器 
            counters[i] = 0; 
        } 
    } 
}

8.选择排序

下面是一个使用Java实现选择排序算法的语句,并带有中文注释:

/**     
 * 选择排序     
 *     
 * @param array     
 *            待排序列     
 */     
public static void selectionSort(int[] array) {    
    int len = array.length;    
    for (int i = 0; i < len - 1; i++) {    
        //记录最小值的下标      
        int minIndex = i;  
        // 找出最小值      
        for (int j = i + 1; j < len; j++) {    
            if (array[minIndex] > array[j]) {     
                minIndex = j;     
            }     
        }  
        // 确保不是本身的位置      
        if (minIndex != i) {     
            int temp = array[minIndex];     
            array[minIndex] = array[i];     
            array[i] = temp;     
        }     
    }     
}

9.桶排序

下面是一个使用Java实现桶排序算法的语句,并带有中文注释:

/**     
 * 桶排序     
 *     
 * @param array     
 *            待排序列     
 * @param bucketSize 
 *            每个桶所能放置多少个不同数值     
 */     
public static void bucketSort(int[] array, int bucketSize) {    
    if (array.length == 0) {    
        return;    
    }    
 
    // 计算桶的数量  
    int minValue = array[0];    
    int maxValue = array[0];    
    for (int i = 1; i < array.length; i++) {    
        if (array[i] < minValue) {    
            minValue = array[i];    
        } else if (array[i] > maxValue) {    
            maxValue = array[i];    
        }    
    }    
    int bucketCount = (maxValue - minValue) / bucketSize + 1;    
    int[][] buckets = new int[bucketCount][0];    
 
    // 利用映射函数将数据分配到各个桶中  
    for (int i = 0; i < array.length; i++) {    
        int index = (array[i] - minValue) / bucketSize;    
        buckets[index] = arrAppend(buckets[index], array[i]);    
    }    
 
    int position = 0;    
    // 对每个桶进行排序,这里使用了快速排序    
    for (int[] bucket : buckets) {    
        quickSort(bucket);    
        for (int value : bucket) {    
            array[position++] = value;    
        }    
    }    
}

10.冒泡排序改进即冒泡改进排序

下面是一个使用Java实现冒泡改进排序算法的语句,并带有中文注释:

/**     
 * 冒泡改进排序     
 *     
 * @param array     
 *            待排序列     
 */     
public static void improvedBubbleSort(int[] array) {    
    int len = array.length;    
    boolean flag;// 标志位,标志是否发生了交换    
    for (int i = 0; i < len - 1; i++) {    
        flag = false;    
        for (int j = 0; j < len - 1 - i; j++) {    
            if (array[j] > array[j + 1]) {    
                int temp = array[j];    
                array[j] = array[j + 1];    
                array[j + 1] = temp;    
                flag = true;    
            }    
        }    
        if (!flag) break;// 如果没有发生交换,说明数列已经有序    
    }    
}

11.快速改进排序,是一种快速排序的变种。与传统的快速排序不同,它使用分治思想和交换排序(如冒泡排序)的结合。这种算法比传统快速排序更有效,因为它采用分治思想,将大的问题划分成小的子问题,减少了比较次数,提高了排序的效率。对比一下:快速排序是一种分治算法,它采用分而治之的方法来解决问题。步骤如下:1)从数组中选择一个基准元素;2)根据基准元素将数组划分成两半;3)对划分后的子数组使用相同的算法递归排序;4)将排序后的子数组合并为一个有序数组。

以下是完整的能够运行的代码:

 

public class ImprovedQuickSort {

    public static void improvedQuickSort(int[] array) {    

        int left = 0;    

        int right = array.length - 1;    

        quickSort(array, left, right);    

    }    

 

    public static void quickSort(int[] array, int left, int right) {    

        if (left >= right) {    

            return;    

        }  

        // 找出基准元素的位置  

        int pivotIndex = partition(array, left, right);  

        // 对左子序列进行排序  

        quickSort(array, left, pivotIndex - 1);  

        // 对右子序列进行排序  

        quickSort(array, pivotIndex + 1, right);  

    }

 

    private static int partition(int[] array, int left, int right) {    

        // 默认基准元素为最左元素  

        int pivot = array[left];  

        while (left < right) {  

            // 从右向左找比基准元素小的元素  

            while (left < right && array[right] >= pivot) {  

                right--;  

            }  

            array[left] = array[right];  

            // 从左向右找比基准元素大的元素  

            while (left < right && array[left] <= pivot) {  

                left++;  

            }  

            array[right] = array[left];  

        }  

        // 将基准元素放回正确位置  

        array[left] = pivot;  

        return left;  

    }

 

    public static void main(String[] args) { 

        int[] array = new int[]{5,3,9,1,7};  

        improvedQuickSort(array);  

        for (int i = 0; i < array.length; i++) {  

            System.out.print(array[i] + " ");  

        }  

    }  

}

12.O(NlogN)排序,O(NlogN)排序法是一种常见的排序算法,它是一种基于分治原理的排序算法,由快速排序算法。其操作过程如下:首先找出基准元素pivot,通常为最左边的元素;然后从右向左遍历整个数组,找到第一个比pivot小的元素arr[right],替换位置arr[left];接着,从左往右遍历整个数组,找到第一个比pivot大的元素arr[left],替换位置arr[right];不断地重复该步骤,直至left==right,然后把pivot放回正确位置arr[left];最后递归对左右子序列重复上面的步骤,完成排序。

下面是O(NlogN)排序法的详细代码:

 

int quickSort(vector<int>&arr, int left, int right)

{

 if (left >= right) 

  return 0;

 int i = left;

 int j = right;

 int pivot = arr[left];

 while (i < j)

 {

  while (i < j && arr[j] >= pivot)

   --j;

  arr[i] = arr[j];

  while (i < j && arr[i] <= pivot)

   ++i;

  arr[j] = arr[i];

 }

 arr[i] = pivot;

 quickSort(arr, left, i-1);

 quickSort(arr, i+1, right);

 return 0; 

}

下面开始JAVA中特殊的排序

1.基数桶排序法是一种采用空间换时间的排序算法。它的基本思想是将数据分成若干(通常是10个)相同大小的桶子,每个桶子中的数据具有相同的基数N,然后对桶子中的每条数据进行比较,并将有序的数据插入另一个链表,最后将该链表转换成数组即为排序后的结果。

 

以JAVA语言实现的基数桶排序法的代码如下:

 

public static void bucketSort(int[] arr) 

{

    if (arr == null || arr.length < 2)

        return;

    // 得到数列的最大值

    int max = Integer.MIN_VALUE;

    for (int i = 0; i < arr.length; i++) {

        max = Math.max(max, arr[i]);

    }

    // 初始化桶

    int[] bucket = new int[max + 1];

    for (int i = 0; i < bucket.length; i++) {

        bucket[i] = 0;

    }

    // 遍历数组,填充桶

    for (int i = 0; i < arr.length; i++) {

        bucket[arr[i]]++;

    }

    // 遍历桶,输出结果

    int i = 0;

    for (int j = 0; j < bucket.length; j++) {

        while(bucket[j]-- > 0) {

            arr[i++] = j;

        }

    }

}

2.外部排序是指当数据量远大于内存容量,无法将所有数据放入内存中进行排序的排序算法。它通过设置一个循环来读取外部文件中的数据,将数据分割为若干小块,并将每一块在内存中排序,之后,再将排序结果写入到一个外部文件中。

 

外部排序的具体步骤如下: 

(1)从外部文件中将数据加载到内存; 

(2)对内存中数据进行排序; 

(3)将排序结果写入到外部文件; 

(4)重复第一步,直到所有的数据都被排序完毕;

(5)将所有已排序的外部文件合并,生成最终的排序结果。以下代码,瑾供参考

外部排序的具体代码实现如下:

// 将指定的数据块写入到外部文件中 
public static void storeChunk(int[] array, File file) throws IOException { 
    try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream( 
        new FileOutputStream(file)))) { 
        for (int d : array) { 
            out.writeInt(d); 
        } 
    } 

// 从外部文件中读取指定大小的数据块 
public static int[] loadChunk(File file, int chunkSize) throws IOException { 
    try (DataInputStream in = new DataInputStream(new BufferedInputStream( 
        new FileInputStream(file)))) { 
        int length = (int) (file.length() / 4); 
        int[] array = new int[Math.min(length, chunkSize)]; 
        for (int i = 0; i < array.length; i++) { 
            array[i] = in.readInt(); 
        } 
        return array; 
    } 

// 对外部文件进行排序
public static void externalSort(File sourceFile, Comparator cmp) throws IOException { 
    // 计算文件中总块数 
    int chunkSize = 8 * 1024 * 1024 / 4; 
    int chunkCount = (int) (sourceFile.length() / chunkSize); 
    
    // 加载数据块并对其进行排序 
    List<int[]> chunks = new ArrayList<>(); 
    for (int i = 0; i < chunkCount; i++) { 
        int[] array = loadChunk(sourceFile, chunkSize); 
        Arrays.sort(array, cmp); 
        chunks.add(array); 
    } 
    
    // 将排序后的数据块一个个合并 
    int[] result = chunks.get(0); 
    for (int i = 1; i < chunks.size(); i++) { 
        result = merge(result, chunks.get(i), cmp); 
    } 
    
    // 将最终结果写入到原始文件中 
    storeChunk(result, sourceFile); 
}

3.内部排序法是指将所有的数据都加载到内存中,然后使用某种算法进行排序。它可以有效避免外部排序法中所需要的I/O操作步骤,从而提升性能和减少时间消耗。

 

内部排序法的具体步骤如下: 

(1)从输入流中读取数据; 

(2)将数据加载到内存中; 

(3)对内存中的数据进行排序; 

(4)将排序结果输出到输出流中。

内部排序的具体代码实现如下:

 

// 从输入流中读取数据

public static int[] loadData(DataInputStream in) throws IOException { 

    int length = in.available() / 4; 

    int[] array = new int[length]; 

    for (int i = 0; i < length; i++) { 

        array[i] = in.readInt(); 

    } 

    return array; 

 

// 将排序结果写入到输出流中

public static void storeData(int[] array, DataOutputStream out) throws IOException { 

    for (int d : array) { 

        out.writeInt(d); 

    } 

 

// 对内存中的数据进行排序 

public static void internalSort(int[] array, Comparator cmp) { 

    Arrays.sort(array, cmp); 

}

 

// 内部排序总操作

public static void internalSort(DataInputStream in, DataOutputStream out, Comparator cmp) throws IOException { 

    int[] array = loadData(in); 

    internalSort(array, cmp); 

    storeData(array, out); 

}

4.交错排序法是一种复杂的排序方法,适用于许多场景,特别是当需要对大量数据进行排序时,它可以极大地提升性能和减少时间消耗。它的原理是把大量数据进行分拆,每一次处理一部分,然后每一部分进行排序,最后再将排好序的数据放到一起。

 

交错排序的具体步骤如下: 

(1)将大量的数据分成N个子集; 

(2)每一个子集独立进行排序; 

(3)将排好序的N个子集合并成一个有序的数据集合。

交错排序的具体代码实现如下:

// 将大量数据分成N个子集
public static <T> List<List<T>> splitData(List<T> data, int subSize) { 
    List<List<T>> subs = new ArrayList<>(); 
    for (int i = 0; i < data.size(); i += subSize) { 
        int endIndex = Math.min(i + subSize, data.size()); 
        subs.add(data.subList(i, endIndex)); 
    } 
    return subs; 

// 每一个子集独立进行排序
public static <T> void internalSort(List<T> sub, Comparator cmp) { 
    Collections.sort(sub, cmp); 
}

// 将排好序的N个子集合并成一个有序的数据集合
 public static <T> List<T> mergeSort(List<List<T>> subs, Comparator cmp) { 
    List<T> ret = new ArrayList<T>(); 
    PriorityQueue<Elem<T>> pq = new PriorityQueue<>(cmp); 
    
    // 将每一个子集中的第一个元素加入pq中
    for (List<T> sub : subs) { 
        if (!sub.isEmpty()) { 
            pq.offer(new Elem<>(sub.get(0), sub, 0)); 
        } 
    } 
    
    // 迭代处理 
    while (!pq.isEmpty()) { 
        Elem<T> elem = pq.poll(); 
        ret.add(elem.val); 
        // 将该子集的下一个元素加入pq中 
        if (elem.index < elem.list.size() - 1) { 
            pq.offer(new Elem<>(elem.list.get(elem.index + 1), elem.list, elem.index + 1)); 
        } 
    } 
    return ret; 

// 交错排序总操作 
public static <T> List<T> mergeSort(List<T> data, int subSize, Comparator cmp) { 
    List<List<T>> subs = splitData(data, subSize); 
    for (List<T> sub : subs) { 
        internalSort(sub, cmp); 
    } 
    return mergeSort(subs, cmp); 
}

当然若要对上面的代码进行完善,可以在交错排序函数中增加一个参数,用于设定参与排序的子集的大小,以便更好地兼顾性能与时间。此外,在分组时也可以考虑增加一个把相近数据分到一块的算法,使得排序更有效率。

后言:还有一些较少被使用的排序算法,如希尔伯特曲线排序、梳排序、块排序、序位排序。可以自行查找。😇😇😇😇

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lidiyscrp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值