5,Java 常用排序算法

58 阅读4分钟

1,冒泡排序

冒泡排序是一种简单的算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就交换位置,这个过程持续对数列的末尾进行,知道整个数列都排序完成。

public static void bubbleSort(int[] arr){   
 for (int i=0;i<arr.length;i++) {        
   for(int j=0;j<arr.length-1-i;j++){
            if(arr[j]>arr[j+1]){
                int tmp = arr[j];
                arr[j]=arr[j+1];
                arr[j+1]= tmp;
            }
        }
    }
}

2,选择排序

选择排序是一种简单的排序算法,它的基本思想是每次从待排序的元素选出最小或者最大的元素,存放在序列的起始位置,知道全部待排序的元素全部排完。

private static void selectionSort(int[] arr) {
    for(int i = 0;i <arr.length;i++){
        int minIndex = i;
        for(int j = i+1;j <arr.length;j++){
            if(arr[minIndex] > arr[j]){
              minIndex = j;
            }
            int temp = arr[i];
            arr[i] =arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

3,插入排序

插入排序的基本思想是将一个未排序的元素插入到已排序的序列中合适的位置,使得插入后的序列仍然有序。

public static void insertSort(int[] arr){
    for(int i=1;i<arr.length;i++){
        int tmp = arr[i];
        int j=i-1;
        while( j>=0 && arr[j]>tmp){
            arr[j+1]=arr[j];
            j--;
        }
        arr[j+1]=tmp;
    }
}

4,希尔排序

希尔排序(Shell sort)是一种改进的插入排序算法,其基本原理和特点如下:

希尔排序的核心思想是将待排序的数组按照一定的间隔(gap)进行分组,然后对每组进行插入排序。随着间隔逐渐减小,最终当间隔为 1 时,就相当于对整个数组进行了一次插入排序。通过这种方式,希尔排序可以在一定程度上克服插入排序在大规模数据下效率较低的问题。

private static void shellSort(int[] arr) {
    int n = arr.length;
    for(int gap = n/2; gap>0; gap /= 2){
        for(int i = gap ; i<n ; i++){
            int tmp = arr[i];
            int j=i;
            for(;j>=gap && arr[j-gap]>tmp;j-=gap){
                arr[j] = arr[j-gap];
            }
            arr[j] = tmp;
        }
    }
}

5,归并排序

归并排序采用分治策略,将待排序的数组不断地分成较小的子数组,直到每个子数组只有一个元素,然后再将这些子数组逐步合并成有序的数组。

public static void sort(int[] a,int low,int high){
    int mid = (low+high)/2;
    if(low<high){
        sort(a,low,mid);
        sort(a,mid+1,high);
        //左右归并
        merge(a,low,mid,high);
    }
}

public static void merge(int[] a, int low, int mid, int high) {
    int[] temp = new int[high-low+1];
    int i= low;
    int j = mid+1;
    int k=0;
    // 把较小的数先移到新数组中
    while(i<=mid && j<=high){
        if(a[i]<a[j]){
            temp[k++] = a[i++];
        }else{
            temp[k++] = a[j++];
        }
    }
    // 把左边剩余的数移入数组
    while(i<=mid){
        temp[k++] = a[i++];
    }
    // 把右边边剩余的数移入数组
    while(j<=high){
        temp[k++] = a[j++];
    } 
   // 把新数组中的数覆盖nums数组
    for(int x=0;x<temp.length;x++){
        a[x+low] = temp[x];
    }
}

6,快速排序

  快速排序采用分支策略,其核心思想是通过一个枢轴元素 pivot,将待排序的数组划分为连个子数组,使得左边子数组中的元素都小于等于枢轴元素,右边子数组中的元素都大于等于枢轴元素,然后分别对这两个子数组进行递归排序最终得到一个有序的数组。

private  static void quickSort(int[] arr,int left,int right ){
    if(arr==null || left >= right || arr.length <=1 ){
        return;
    }
    int mid=partition(arr,left,right);
    quickSort(arr,left,mid);
    quickSort(arr,mid+1,right);
}

private static int partition(int[]arr,int left,int right ){
    int temp = arr[left];
    while (right > left) { 
       // 先判断基准数和后面的数依次比较
        while (temp <= arr[right] && left < right) {
            --right;
        }
        // 当基准数大于了 arr[right],则填坑
        if (left < right) {
            arr[left] = arr[right];
            ++left;
        }
       // 现在是 arr[right] 需要填坑了
        while (temp >= arr[left] && left < right) {
            ++left;
        }
        if (left < right) {
            arr[right] = arr[left];
            --right;
        } 
   }
    arr[left] = temp;
    return left;
}

7,堆排序

      堆排序利用了二叉堆(通常是最大堆或最小堆)的数据结构特性。最大堆的特点是每个节点的值都大于或等于其左右子节点的值。通过构建最大堆,然后不断地将堆顶元素(最大值)与未排序部分的最后一个元素交换,再调整剩余元素为最大堆,逐步实现整个数组的排序。

      

public class HeapSort {
    public static void heapSort(int[] arr) {
        int n = arr.length;
        // 构建最大堆
        for (int i = n / 2 - 1; i >= 0; i--) {
            heapify(arr, n, i);
        }
        // 排序过程
        for (int i = n - 1; i > 0; i--) {
            // 交换堆顶元素和当前未排序部分的最后一个元素
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            // 对新的堆顶元素进行调整
            heapify(arr, i, 0);
        }
    }

    private static void heapify(int[] arr, int n, int i) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        // 如果左子节点比当前最大节点大,更新最大节点索引
        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }
        // 如果右子节点比当前最大节点大,更新最大节点索引
        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }
        // 如果最大节点不是当前节点,进行交换并递归调整
        if (largest!= i) {
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;
            heapify(arr, n, largest);
        }
    }

    public static void main(String[] args) {
        int[] arr = {4, 10, 3, 5, 1};
        heapSort(arr);
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

8,计数排序

计数排序是一种非比较排序算法,它的基本思想是统计数组中每个元素出现的次数,然后根据元素出现的次数依次将元素放入有序的数组中。 计数排序时间复杂度为O(n+k),其中k为待排序的元素的最大值。

public class CountingSort {
    public static int[] countingSort(int[] arr) {
        if (arr.length == 0) {
            return arr;
        }

        int maxVal = findMax(arr);
        int minVal = findMin(arr);
        int range = maxVal - minVal + 1;

        int[] count = new int[range];
        int[] output = new int[arr.length];

        // 统计每个元素的出现次数
        for (int num : arr) {
            count[num - minVal]++;
        }

        // 计算累计出现次数
        for (int i = 1; i < count.length; i++) {
            count[i] += count[i - 1];
        }

        // 从后往前遍历原数组,将元素放置到正确的位置
        for (int i = arr.length - 1; i >= 0; i--) {
            output[count[arr[i] - minVal] - 1] = arr[i];
            count[arr[i] - minVal]--;
        }

        return output;
    }

    private static int findMax(int[] arr) {
        int max = arr[0];
        for (int num : arr) {
            if (num > max) {
                max = num;
            }
        }
        return max;
    }

    private static int findMin(int[] arr) {
        int min = arr[0];
        for (int num : arr) {
            if (num < min) {
                min = num;
            }
        }
        return min;
    }

    public static void main(String[] args) {
        int[] arr = {4, 2, 2, 8, 3, 3, 1};
        int[] sortedArr = countingSort(arr);
        for (int num : sortedArr) {
            System.out.print(num + " ");
        }
    }
}

9,桶排序

桶排序是一种非比较排序算法,它的基本思想是将待排序的数组分到有限数量的桶里,然后对每个桶进行排序,最后依次将所有桶中的元素取出来,组成有序的数组。 桶排序的时间复杂度为O(n),其中n为待排序元素的个数。

import java.util.ArrayList;
import java.util.List;

public class BucketSort {
    public static double[] bucketSort(double[] arr) {
        int n = arr.length;
        List<Double>[] buckets = new ArrayList[n];

        // 创建桶
        for (int i = 0; i < n; i++) {
            buckets[i] = new ArrayList<>();
        }

        // 将元素分配到桶中
        for (double num : arr) {
            int bucketIndex = (int) (num * n);
            buckets[bucketIndex].add(num);
        }

        // 对每个桶进行排序
        for (int i = 0; i < n; i++) {
            buckets[i].sort(null);
        }

        // 合并桶中的元素
        int index = 0;
        for (List<Double> bucket : buckets) {
            for (double num : bucket) {
                arr[index++] = num;
            }
        }

        return arr;
    }

    public static void main(String[] args) {
        double[] arr = {0.42, 0.32, 0.33, 0.52, 0.37, 0.47, 0.51};
        double[] sortedArr = bucketSort(arr);
        for (double num : sortedArr) {
            System.out.print(num + " ");
        }
    }
}

10,基数排序

基数排序是一种非比较排序算法,它的基本思想是将待排序的数组按照位数(个位、十位、百位)进行划分,然后依次对每个位上的数字进行排序,最终得到有序的数组。 基数排序的时间复杂度为O(d(n+k)),其中d为最大元素的位数,n为待排序元素的个数,k为桶的个数。

import java.util.ArrayList;
import java.util.List;

public class RadixSort {
    public static int[] radixSort(int[] arr) {
        int max = findMax(arr);
        int exp = 1;
        while (max / exp > 0) {
            List<Integer>[] buckets = new ArrayList[10];
            for (int i = 0; i < 10; i++) {
                buckets[i] = new ArrayList<>();
            }
            for (int num : arr) {
                int bucketIndex = (num / exp) % 10;
                buckets[bucketIndex].add(num);
            }
            int index = 0;
            for (List<Integer> bucket : buckets) {
                for (int value : bucket) {
                    arr[index++] = value;
                }
            }
            exp *= 10;
        }
        return arr;
    }

    private static int findMax(int[] arr) {
        int max = arr[0];
        for (int num : arr) {
            if (num > max) {
                max = num;
            }
        }
        return max;
    }

    public static void main(String[] args) {
        int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
        int[] sortedArr = radixSort(arr);
        for (int num : sortedArr) {
            System.out.print(num + " ");
        }
    }
}