十种常见的排序算法

声明:作者比较懒,写这篇文章是为了以后用到的时候CV,所以注释写的不详细,也没有针对算法进行讲解,敬请谅解。

目录

冒泡排序

选择排序

插入排序

归并排序

快速排序

堆排序

希尔排序

计数排序

桶排序

基数排序

测试代码

总结

冒泡排序

    public static void bubbleSort(int[] arr) {
        int temp = 0;
        //外层for循环表示排序的趟数
        for (int i = 0; i < arr.length - 1; i++) {
            //内层for循环表示这一趟需要比较的次数
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

        System.out.println("bubbleSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

选择排序

    public static void selectSort(int[] arr) {
        int temp = 0, min = 0;
        //外层for循环表示排序的趟数
        for (int i = 0; i < arr.length - 1; i++) {
            min = i;
            //循环查找最小值,记录最小值的index
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[min]) {
                    min = j;
                }
            }
            if (min != i) {
                temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
            }
        }
        System.out.println("selectSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

插入排序

    public static void insertSort(int[] arr) {
        //插入排序在序列基本有序的前提下效率是很高的,所以从后往前插入是一个更好的选择
        int temp = 0;
        //外循环表示排序的趟数
        //每次选取第i+1张牌,从后往前开始比较,插入到比它小的第一张牌的后面
        for (int i = 1; i < arr.length; i++) {
            int positon = i;
            for (int j = positon - 1; j >= 0; j--) {
                if (arr[positon] < arr[j]) {
                    temp = arr[positon];
                    arr[positon] = arr[j];
                    arr[j] = temp;
                    positon--;
                }
            }
        }
        System.out.println("insertSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

归并排序

     public static void mergeSort(int[] arr) {
        int[] temp = new int[arr.length];
        merge(arr, temp, 0, arr.length - 1);
        System.out.println("nmergeSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

    public static void merge(int[] arr, int[] temp, int left, int right) {
        //当left==right时,已经达到最小数组
        if (left < right) {
            int middle = (left + right) / 2;
            //分而治之,把原数组分成左右两个数组
            merge(arr, temp, left, middle);
            merge(arr, temp, middle + 1, right);
            //把分而治之的两个数组归并在一起
            mergeSortedArray(arr, temp, left, middle, right);
        }
    }

    public static void mergeSortedArray(int[] arr, int[] temp, int left, int middle, int right) {
        int i = left;
        int j = middle + 1;
        int k = 0;
        //双指针进行比较,当其中一个指针走到末尾时结束循环
        while (i <= middle && j <= right) {
            temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        //此时其中一个指针已经走到了末尾,依次赋值完成归并
        while (i <= middle) {
            temp[k++] = arr[i++];
        }
        while (j <= right) {
            temp[k++] = arr[j++];
        }
        //将排序完成后temp数组中的值放回原数组中
        for (i = 0; i < k; i++) {
            //i + left表示temp中的值在arr中对应的位置
            arr[i + left] = temp[i];
        }
    }

快速排序

    public static void quickSort(int[] arr) {
        quick(arr, 0, arr.length - 1);
        System.out.println("quickSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

    public static void quick(int[] arr, int low, int high) {
        //当low>=high时,已经完成排序
        if (low >= high) {
            return;
        }
        int i = low, j = high;

        //选择基准值这里选择的是数组中间的那个元素为基准值
//        int pivot = arr[(low + high) / 2];
//        int temp = 0;
//        temp = arr[low];
//        arr[low] = arr[(low + high) / 2];
//        arr[(low + high) / 2] = temp;

        int pivot = arr[low];

        //双指针让基准归位
        while (i < j) {
            //从后往前走,当找到比pivot小的值的时候退出循环
            while (arr[j] >= pivot && i < j) {
                j--;
            }
            //第一次运行时,相当于覆盖了pivot的值
            // 把比pivot小的值移到arr[i]的位置,并把arr[j]的位置让了出来
            if (i < j) {
                arr[i] = arr[j];
            }
            //从前往后走,当找到比pivot大的值的时候退出循环
            while (arr[i] <= pivot && i < j) {
                i++;
            }
            // 把比pivot大的值移到arr[i]的位置,并把arr[i]的位置让了出来
            if (i < j) {
                arr[j] = arr[i];
            }
        }
        arr[i] = pivot;//基准归位
        //分成左右两个数组继续运行
        quick(arr, low, i - 1);
        quick(arr, i + 1, high);
    }

堆排序

    public static void heapSort(int[] arr) {
        int last = arr.length - 1;

        //建立堆
        buildMaxHeap(arr);

        //把最大堆的根结点放到数组的末尾,并限制数组的可操作长度
        //然后调整为最大堆,并重复以上操作,直到last=0
        while (last > 0) {
            swap(arr, 0, last--);
            adjustHeap(arr, 0, last);
        }
        System.out.println("heapSort后的数组:");
        System.out.println(Arrays.toString(arr));

    }

    public static void buildMaxHeap(int[] arr) {
        int len = arr.length;
        //从最后一个结点的父结点开始调整
        for (int i = (len - 1) / 2; i >= 0; i--) {
            adjustHeap(arr, i, len - 1);
        }
    }

    //i表示即将进行调整的元素的位置,last表示未调整完成的数组尾
    //下沉调整,类比于堆的删除操作
    public static void adjustHeap(int[] arr, int i, int last) {
        int temp = arr[i];//保存父结点和两个子结点中的最大值
        int largest = i;//记录父结点与两个子结点中的最大值的index
        int left = 0, right = 0;//表示两个子结点的index

        //当左结点大于最后一个结点时退出循环
        while (left <= last) {
            left = 2 * i + 1;
            right = left + 1;


            //与左孩子进行比较
            if (left <= last && temp < arr[left]) {
                largest = left;
                temp = arr[largest];
            }
            //与右孩子进行比较
            if (right <= last && temp < arr[right]) {
                largest = right;
                temp = arr[largest];
            }
            //在这一轮中i的值没有发生改变,此时已经调整好,退出循环
            if (largest == i) {
                break;
            }
            //完成交换,并把i指向交换后的index继续调整
            swap(arr, i, largest);
            i = largest;
            temp = arr[i];
        }
    }
    //交换函数
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

希尔排序

    public static void shellSort(int[] arr) {

        //第一种增量是Donald Shell提出的增量,即折半降低直到1
        //第二种增量Hibbard:{1, 3, ..., 2k-1}
        //第三种增量Sedgewick:{1, 5, 19, 41, 109...}该序列中的项或者是9*4^i - 9*2^i + 1或者是4^i - 3*2^i + 1

        //第一层循环表示增量序列
        //第二三层表示按照增量序列进行插入排序
        //按照第一种增量序列进行希尔排序
//        for (int gap = arr.length / 2; gap >= 1; gap /= 2) {
//            for (int i = gap; i < arr.length; i += gap) {
//                int positon = i;
//                for (int j = positon - gap; j >= 0; j -= gap) {
//                    if (arr[positon] < arr[j]) {
//                        swap(arr, positon, j);
//                        positon -= gap;
//                    }
//                }
//
//          }

        //Kunth 增量序列:1,4,13,40.121, ...(3n+1)
        int gap = 1;
        while (gap < arr.length / 3) {
            gap = gap * 3 + 1;
        }
        for (; gap >= 1; gap /= 3) {
            for (int i = gap; i < arr.length; i += gap) {
                int positon = i;
                for (int j = positon - gap; j >= 0; j -= gap) {
                    if (arr[positon] < arr[j]) {
                        swap(arr, positon, j);
                        positon -= gap;
                    }
                }
            }
        }
        System.out.println("shellSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }
    //交换函数
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

计数排序

    //计数排序是一个牺牲空间换取时间的排序方法
    public static void countSort(int[] arr) {
        //获得数组的范围min-max
        int max = arr[0], min = arr[0];
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }

        //将数组中的值统计到count中
        int[] count = new int[max - min + 1];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i] - min]++;
        }

        //读取count中的数,完成赋值
        int position = 0;
        for (int i = 0; i < arr.length; i++) {
            while (count[position] == 0) {
                position++;
            }
            arr[i] = position + min;
            count[position]--;
        }

        System.out.println("countSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

桶排序

    public static void bucketSort(int[] arr) {
        int max = arr[0], min = arr[0];
        int len = arr.length;
        for (int i = 0; i < len; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }

        //桶的数量,桶的数量越多,速度越快,这里选取的桶的数量为(max-min)/len + 1
        int bucketNum = (max - min) / len + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucketArr.add(new ArrayList<Integer>());
        }

        //把数组中的元素放到桶里
        for (int i = 0; i < len; i++) {
            int positon = (arr[i] - min) / len;
            bucketArr.get(positon).add(arr[i]);
        }

        //调用其他的排序方法对桶内元素进行排序
        for (int i = 0; i < bucketNum; i++) {
            Collections.sort(bucketArr.get(i));
        }

        //把桶拼接到一起
        int position = 0;
        for (int i = 0; i < bucketNum; i++) {
            for (int j = 0; j < bucketArr.get(i).size(); j++) {
                arr[position++] = bucketArr.get(i).get(j);
            }
        }
        System.out.println("bucketSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

基数排序

    public static void radixSort(int[] arr) {
        int len = arr.length;
        int[][] radixArr = new int[10][arr.length];
        int[] counter = new int[10];

        //找到数组中最大的值,以此来判断排序的次数
        int max = 0;
        for (int i = 0; i < len; i++) {
            max = Math.max(max, arr[i]);
        }

        //n用以对arr[i]位数的处理
        int n = 1;
        while (max > 0) {
            //将arr中的值放到radixArr中
            for (int i = 0; i < len; i++) {
                int index = (arr[i] / n) % 10;
                radixArr[index][counter[index]] = arr[i];
                counter[index]++;
            }

            //把radixArr中的数据放回原数组
            int position = 0;
            for (int i = 0; i < radixArr.length; i++) {
                for (int j = 0; j < counter[i]; j++) {
                    arr[position++] = radixArr[i][j];
                }
            }
            //重置计数器
            for (int i = 0; i < 10; i++) {
                counter[i] = 0;
            }
            max /= 10;
            n *= 10;
        }
        System.out.println("radixSort后的数组:");
        System.out.println(Arrays.toString(arr));
    }

测试代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Sort {
    public static void main(String[] args) {
        int[] arr = new int[1000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
        System.out.println("原数组:");
        System.out.println(Arrays.toString(arr));
        //打乱数组
        shuffle(arr);
        //冒泡排序升序
        bubbleSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //选择排序升序
        selectSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //选择排序升序
        insertSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //归并排序升序
        mergeSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //快速排序升序
        quickSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //堆排序升序
        heapSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //希尔排序升序
        shellSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //希尔排序升序
        countSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //希尔排序升序
        bucketSort(arr);
        //排序测试
        testIncreasing(arr);

        //打乱数组
        shuffle(arr);
        //希尔排序升序
        radixSort(arr);
        //排序测试
        testIncreasing(arr);
    }

    //打乱数组
    public static void shuffle(int[] arr) {
        Random random = new Random();
        for (int i = 0; i < arr.length; i++) {
            int j = i + random.nextInt(arr.length-i);
            swap(arr, i, j);
        }
        System.out.println("打乱后的数组");
        System.out.println(Arrays.toString(arr));
    }

//    //计时器
//    public static void timer() {
//        //获取程序运行时间的代码,可以用于比较不同算法之间的效率,数据量较小时,
//        //可以把System.currentTimeMillis()换成System.nanoTime()
//        long startTime = System.currentTimeMillis();     //获取开始时间
//        //doSomething();   //要测运行时间的程序代码
//        long overTime = System.currentTimeMillis();      //获取结束时间
//        System.out.println("程序运行时间为:" + (overTime - startTime) + "毫秒");
//    }

    //测试arr是否是递增序列
    public static void testIncreasing(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                System.out.println("非递增序列!!!\n");
                return;
            }
        }
        System.out.println("递增序列,排序成功!\n");
    }
}

总结

排序算法时间复杂度空间复杂度稳定性
冒泡排序O(n^{2})O(1)稳定
插入排序O(n^{2})O(1)不稳定
选择排序O(n^{2})O(1)稳定
归并排序O(nlogn)O(n)稳定
快速排序O(nlogn)O(nlogn)不稳定
堆排序O(nlogn)O(1)不稳定
希尔排序O(nlogn)O(nlogn)不稳定
计数排序O(n+k)

 O(n+k)

稳定
桶排序O(n+k)O(n+k)稳定
基数排序O(n*k)O(n+k)稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不想写代码的Rayoung

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

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

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

打赏作者

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

抵扣说明:

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

余额充值