八大排序算法 Java实现

一、插入排序

稳定排序

模板

class Sort {
    public static <AnyTpye extends Comparable<? super AnyTpye>> void insertionSort(AnyTpye[] a){ //Comparable可以比较的数或对象
        int j;
        for (int p =1;p < a.length;p++){ //默认a[0]是有序的,所以从1开始
            AnyTpye tmp = a[p]; //暂存要插入的p号元素
            //把p号元素从本身开始往前比较,直到比前一个数大,终止循环,可以插入
            for (j = p;j>0 && tmp.compareTo(a[j-1])<0;j--) 
                a[j] = a[j-1];
            a[j] = tmp;
        }
    }
}

应用

import java.util.Arrays;

class Sort{
    public static void insertionSort(int[] a){
        int j;
        for (int p = 1; p < a.length; p++) {
            int tmp = a[p];
            for (j = p;j>0 && tmp<a[j-1];j--){
                a[j] = a[j-1];
            }
            a[j] = tmp;
        }
    }

    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        insertionSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

分析

时间复杂度O(N^2)

N个互异数的数组的平均逆序数是N(N-1)/4

通过交换相邻元素进行排序的任何算法平均都需要Ω(N^2)时间

二、希尔排序

非稳定排序

模板

class Sort{
    public static <AnyTpye extends Comparable<? super AnyTpye>> void shellSort(AnyTpye[] a){
        int j;
        //在不同的gap上用插入排序
        for (int gap = a.length/2;gap > 0;gap /= 2)
            for (int i = gap;i < a.length;i++){
                AnyTpye tmp = a[i];
                for (j = i;j>=gap && tmp.compareTo(a[j-gap])<0;j -= gap)
                    a[j] = a[j-gap];
                a[j] = tmp;
            }
    }
}

应用

import java.util.Arrays;

class Sort{
    public static void shellSort(int[] a){
        int j;
        for (int gap = a.length/2;gap > 0;gap /= 2){
            for (int i = gap;i < a.length;i++){
                int tmp = a[i];
                for (j = i;j >= gap && tmp < a[j-gap];j -= gap){
                    a[j] = a[j-gap];
                }
                a[j] = tmp;
            }
        }
    }

    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        shellSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

分析

使用希尔增量({1,4,8...,2^k})的希尔排序,最坏时间复杂度O(N^2)

使用 Hibbard 增量({1,3,7,...2^k-1})的希尔排序,最坏时间复杂度O(N^1.5),它跟希尔增量的区别在于相邻增量没有公因数

最优的增量序列:{1,5,19,41,109,...,9*(4^k-2^k)+1,4^i-3*2^i+1,...}

三、选择排序

import java.util.Arrays;

class Sort{
    private static void chooseSort(int[] nums){
        for (int i = 0; i < nums.length-1; i++) {
            int k = i;
            for (int j = i+1; j < nums.length; j++) {
                if (nums[k] > nums[j]) k = j; //选出最小数的角标
            }
            if (k!=i){ //最小的不是自己则需要拿到前面
                int tmp = nums[i];
                nums[i] = nums[k];
                nums[k] = tmp;
            }
        }
    }

    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        chooseSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

四、堆排序

完全二叉树,第 i 个结点为例,左孩子为 2i+1,右孩子为 2i+2

public class HeapSort {
    public static void main(String[] args) {
//        int[] arr = {5, 1, 7, 3, 1, 6, 9, 4};
        int[] arr = {16, 7, 3, 20, 17, 8};

        heapSort(arr);

        for (int i : arr) {
            System.out.print(i + " ");
        }
    }


    //创建堆 
    private static void heapSort(int[] arr) {
        //创建堆
        for (int i = (arr.length - 1) / 2; i >= 0; i--) {
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(arr, i, arr.length);
        }

        //调整堆结构+交换堆顶元素与末尾元素
        for (int i = arr.length - 1; i > 0; i--) {
            //将堆顶元素与末尾元素进行交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;

            //重新对堆进行调整,调前i个就行了
            adjustHeap(arr, 0, i);
        }
    }

    //调整堆
    private static void adjustHeap(int[] arr, int parent, int length) {
        //将temp作为父节点
        int temp = arr[parent];
        //左孩子
        int lChild = 2 * parent + 1;

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

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

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

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

五、冒泡排序

import java.util.Arrays;

class Sort{
    private static void chooseSort(int[] nums){
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j+1]){
                    int tmp = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = tmp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        chooseSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

六、快速排序

import java.util.Arrays;

class Sort{
    private static void quickSort(int[] nums){
        quickSort(nums, 0, nums.length - 1);
    }

    private static void quickSort(int[] nums, int l, int r) {
        if (l >= r) return;
        int index = helper(nums,l,r);
        quickSort(nums,l,index-1);
        quickSort(nums,index+1,r);
    }

    private static int helper(int[] nums,int l,int r){
        int i = l;
        int j = r;
        int x = nums[i];
        while (i < j){
            while (i < j && nums[j] >= x){
                j--;
            }
            if (i < j){
                nums[i] = nums[j];
            }
            while (i < j && nums[i] <= x){
                i++;
            }
            if (i < j){
                nums[j] = nums[i];
            }
        }
        nums[i] = x;
        return i;
    }

    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        quickSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

七、归并排序

import java.util.Arrays;

class Sort{
    private static void mergeSort(int[] nums){
        mergeSort(nums,0,nums.length-1);
    }

    private static void mergeSort(int[] nums, int left, int right) {
        if (left < right){
            int center = (left + right) / 2;
            mergeSort(nums,left,center); //递归调用
            mergeSort(nums,center+1,right);
            merge(nums,left,center,right); //连接两个有序数组
        }
    }

    private static void merge(int[] nums, int left, int center, int right) {
        int[] tmpNums = new int[nums.length];
        int mid = center + 1; //后边数组的开始
        int third = left;
        int tmp = left; //留到最后拷贝数组用
        while (left <= center && mid <= right){
            if (nums[left] <= nums[mid]){
                tmpNums[third++] = nums[left++];
            }else {
                tmpNums[third++] = nums[mid++];
            }
        }
        while (mid <= right){
            tmpNums[third++] = nums[mid++];
        }
        while (left <= center){
            tmpNums[third++] = nums[left++];
        }
        while (tmp <= right){
            nums[tmp] = tmpNums[tmp++];
        }
    }
    
    public static void main(String[] args) {
        int[] nums = {8,34,64,51,32,21};
        mergeSort(nums);
        System.out.println(Arrays.toString(nums));
    }
}

八、基排序

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
                194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};

        radixSort(arr);

        System.out.println(Arrays.toString(arr));
    }

    private static void radixSort(int[] arr) {
        //待排序列最大值
        int max = arr[0];
        int exp;//指数

        //计算最大值,确定最高位数
        for (int anArr : arr) {
            if (anArr > max) {
                max = anArr;
            }
        }

        //从个位开始,对数组进行排序
        for (exp = 1; max / exp > 0; exp *= 10) {
            //存储待排元素的临时数组
            int[] temp = new int[arr.length];
            //分桶个数
            int[] buckets = new int[10];

            //将数据出现的次数存储在buckets中
            for (int value : arr) {
                //(value / exp) % 10 :value的最底位(个位)
                buckets[(value / exp) % 10]++;
            }

            //更改buckets[i],
            for (int i = 1; i < 10; i++) {
                buckets[i] += buckets[i - 1];
            }

            //将数据存储到临时数组temp中
            for (int i = arr.length - 1; i >= 0; i--) {
                temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
                buckets[(arr[i] / exp) % 10]--;
            }

            //将有序元素temp赋给arr
            System.arraycopy(temp, 0, arr, 0, arr.length);
        }

    }
}
posted @ 2020-07-14 17:09  鹏懿如斯  阅读(507)  评论(0编辑  收藏  举报