十大经典排序算法代码演示

import java.util.*;

//https://www.cnblogs.com/onepixel/articles/7674659.html    十大经典排序算法(动图演示)
public class Sort {
    public static void main(String[] args) {
        //Random random1 = new Random();    //随机数对象
        int[] arr1 = new int[10];
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] = Math.abs(new Random().nextInt(10));//产生0~9的随机数
            //System.out.print(new Random().nextInt(10) + 1 + " ");//产生1~10的随机数
        }
        System.out.println("初始化数组:" + Arrays.toString(arr1));
        Arrays.sort(arr1); //Arrays类排序方法
//        selectSort(arr1); //选择排序
//        insertSort(arr1); //插入排序
//        shellSort(arr1);    //希尔排序(分组插入排序)
//        bubbleSort(arr1);   //冒泡排序
//        bubbleSort2(arr1);   //冒泡排序优化
//        heapSortMax(arr1); //堆排序(最大堆)升序
//        heapSortMin(arr1); //堆排序(最小堆)降序
//        quickSort(arr1, 0, arr1.length - 1);  //快排,指定区间,low起始位置,high尾位置
//        mergeSort(arr1);    //归并排序
//        countingSort(arr1); //计数排序
//        radixSort(arr1);    //基数排序
//        bucketSort(arr1);   //桶排序
        System.out.println("结果:" + Arrays.toString(arr1));

        //字符串排序
        System.out.println("字符串排序:");
        String[] str = {"d", "a", "c"};
        System.out.println("原字符串数组:" + Arrays.toString(str));
        stringSort(str);
        System.out.println("排序后:" + Arrays.toString(str));

        //字符串中的数排序
        System.out.println("字符串中的数排序:");
        String numStr = "20 78 9 -7 88  36 29";
        System.out.println("初始化字符串中的数:" + numStr);
        numStr = stringNumberSort(numStr);
        System.out.println("排序后字符串中的数:" + numStr);

        //对一个四位数排序
        int num = 1695;
        System.out.println("从小到大排序:" + intSortMin(num));
        System.out.println("从大到小排序:" + intSortMax(num));

        //对两个有序数组合并并且排序
        int[] arr2 = {6, 8, 13};
        int[] arr3 = {1, 3, 8, 17};
        System.out.println("合并排序前的两个数组:\n" + Arrays.toString(arr2) + "\n" + Arrays.toString(arr3));
        System.out.println("合并排序后:" + Arrays.toString(addSort(arr2, arr3)));

        //对字符串长度排序
        TreeSet<String> ts = new TreeSet<>(new CompareToByStringLength());
        ts.add("aaaaa");
        ts.add("zz");
        ts.add("haha");
        ts.add("abhxxdad");
        for (String t : ts) {
            System.out.println(t);
        }
    }

    //桶排序(计数排序)  数据非负数
    private static void countingSort(int[] arr) {
        int max = arr[0];//定义最大值为该数组的第一个数
        for (int i = 0; i < arr.length; i++) {//找出数组中最大值,用来确定标记数组的长度
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        int[] book = new int[max + 1];//定义标记数组,初始化全部为0
        for (int i = 0; i < arr.length; i++) {
            book[arr[i]]++;
            ;    //统计arr中不同元素个数
        }
        int index = 0;//用于将结果存回元数组的下标
        for (int i = 0; i < book.length; i++) {
            for (int j = 0; j < book[i]; j++) {//遍历每个元素
                arr[index++] = i;//将结果返回原数组
            }
        }
    }

    //基数排序
    private static void radixSort(int[] arr) {
        int max = arr[0];//定义最大值为该数组的第一个数
        for (int i = 0; i < arr.length; i++) {//找出数组中最大最小值
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        int d = 1;  //确定最大数有几位
        while (max / 10 != 0) {
            d++;
            max = max / 10;
        }
        //bucket的第一维表示可能的余数0-9   (arr.length)表示个位数,十位数...相同的最多arr.length个(就算全部元素放在一个桶中也能放下)
        int[][] bucket = new int[10][arr.length];
        int[] order = new int[10];//数组order[i]用来表示该位是i的数的个数(计数排序)
        int m = 1;//控制键值排序依据在哪一位
        int n = 1;//如元素798的个位桶index=(798/1)%10=8, 十位桶index=(798/10)%10=9,百位桶index=(798/100)%10=7,n为上式中的1、10、100
        while (m <= d) {//如果键值未达到最高位
            for (int i = 0; i < arr.length; i++) {
                int index = ((arr[i] / n) % 10);//依据位的值,比如第一次就是个位上的值
                bucket[index][order[index]] = arr[i];//将元素放入对应桶
                order[index]++;//为放入同桶的下一个元素做准备
            }
            int k = 0;//自增计数用
            for (int i = 0; i < bucket.length; i++) {
                if (order[i] != 0) {//如果键值依据位对应有元素,比如第一次个位为8的,不是0个
                    for (int j = 0; j < order[i]; j++) {
                        arr[k] = bucket[i][j];//将桶中数倒回
                        k++;
                    }
                }
                order[i] = 0;//重置,便于下次同一键值的元素计数
            }
            n *= 10;//第一次1、第二次10、第三次100...
            m++;//键值依据位++,第一次个位,第二次十位...
        }
    }

    //桶排序
    private static void bucketSort(int[] arr) {
        int max = arr[0];//定义最大值为该数组的第一个数
        for (int i = 0; i < arr.length; i++) {//找出数组中最大值
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        int d = 0;  //确定最大数有几位
        while (max != 0) {
            d++;
            max = max / 10;
        }
        //创建桶  bucket的第一维表示10个桶,arr.length + 1这里每个第一列用来存放对应行元素个数,所以+1
        int[][] bucket = new int[10][arr.length + 1];
        for (int i = 1; i <= d; i++) {//i 取余的位置开始从个位,十位...d
            int divisor = 1;//除数    第一次1、第二次10、第三次100...
            for (int j = 1; j < i; j++) {
                divisor *= 10;
            }
            for (int j = 0; j < arr.length; j++) {
                int numOfDigist = arr[j] / divisor % 10;//得到个位数的值,十位数的值...
                int count = ++bucket[numOfDigist][0];//该桶中元素个数count
                bucket[numOfDigist][count] = arr[j];
                //元素入对应桶   这里的bucket每个第一列用来存放对应行元素个数
            }
            int index = 0;//自增计数用
            for (int j = 0; j < bucket.length; j++) {
                for (int k = 1; k <= bucket[j][0]; k++) {
                    arr[index] = bucket[j][k];//将桶中数倒回
                    index++;
                }
            }
            for (int j = 0; j < bucket.length; j++) {
                Arrays.fill(bucket[j], 0);//重置桶
            }
        }
    }

    //对两个有序数组合并并且排序(归并排序的基础) 1 5 8      3  9
    private static int[] addSort(int[] arr2, int[] arr3) {
        int i = 0;    //第一个数组起始位位置
        int j = 0;    //第二个数组起始位位置
        int[] newarr = new int[arr2.length + arr3.length];//新数组
        int k = 0;    //新数组起始位置
        while (i <= arr2.length - 1 && j <= arr3.length - 1) { //选择两个数组中最小值放入新数组
            if (arr2[i] < arr3[j]) {
                newarr[k++] = arr2[i++];
            } else {
                newarr[k++] = arr3[j++];
            }
        }
        while (i <= arr2.length - 1) {  //如果第一个数组数据没有遍历完,但第二个数组遍历完,此时将第一个数组未遍历完数据放入新数组
            newarr[k++] = arr2[i++];
        }
        while (j <= arr3.length - 1) {
            newarr[k++] = arr3[j++];
        }
        return newarr;
    }

    //归并排序1
    private static void mergeSort(int[] arr) {
        int[] newarr = new int[arr.length];
        mergeSort2(arr, 0, arr.length - 1, newarr);
    }

    //归并排序2
    private static void mergeSort2(int[] arr, int first, int last, int[] newarr) {
        if (first < last) {   //不断拆分,直到每组仅剩一个元素
            int mid = (first + last) / 2;
            mergeSort2(arr, first, mid, newarr);    //左边有序
            mergeSort2(arr, mid + 1, last, newarr);     //右边有序
            merge(arr, newarr, first, mid, last);    //再将二个有序数列合并
        }
    }

    //归并3    将arr中0 ~ mid 位置 和 mid + 1 ~ 尾位置high,归并至newarr中(先假设这两个区间就是两个有序序列)
    private static void merge(int[] arr, int[] newarr, int low, int mid, int high) {
        int i = low;    //第一个区间起始位位置,mid为结尾位置
        int j = mid + 1;    //第二个区间起始位位置,high为结尾位置
        int k = 0;    //新数组起始位置
        while (i <= mid && j <= high) { //选择两个区间中最小值放入新数组
            if (arr[i] < arr[j]) {
                newarr[k++] = arr[i++];
            } else {
                newarr[k++] = arr[j++];
            }
        }
        while (i <= mid) {  //如果第一个区间数据没有遍历完,但第二个区间遍历完,此时将第一个区间未遍历完数据放入新数组
            newarr[k++] = arr[i++];
        }
        while (j <= high) {
            newarr[k++] = arr[j++];
        }
        for (i = 0; i < k; i++) { // 将已排好序的元素放回对应位置
            arr[low + i] = newarr[i];
        }
    }

    //选择排序
    private static void selectSort(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }
        int minIndex = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            minIndex = i;   //无序区的最小数据数组下标
            for (int j = i + 1; j < arr.length; j++) {
                //在无序区中找到最小数据并保存其数组下标
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                //如果不是无序区的最小值位置不是默认的第一个数据(最小),则交换之。
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
        /*每一次从待排序的数据元素中选出最小(或最大)的一个元素,
        存放在序列的起始位置,直到全部待排序的数据元素排完*/
    }

    //插入排序(在元素个数少且基本有序的数组排序中效率高)
    private static void insertSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j > 0; j--) {
                if (arr[j] < arr[j - 1]) {  //一直与前一个元素比较,若小与前一个元素
                    int temp = arr[j];  //则取出此元素,与前一个元素交换值
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                } else {    //接下来是无用功直接跳出,因为前面已经排好序
                    break;
                }
            }
            //System.out.println("第" + i + "趟排序:" + Arrays.toString(arr));
        }
        //整体效果:从第二个位置开始,找到一个小的元素,一直往前比较,若前面值大,则交换,否则跳出循环(前面元素已排好序)
    }

    //希尔排序(分组插入排序)
    private static void shellSort(int[] arr) {
        int d = arr.length;//组数
        do {
            d = d / 3 + 1;  //减少分组直到为1
            for (int x = 0; x < d; x++) {   //循环不同组
                for (int i = x + d; i < arr.length; i += d) {   //循环每组数据
                    int temp = arr[i];//记录每组的第二个数据(第一次执行时,之后就是每组无序区起始位置,也就是有序区的末尾)
                    int flag = i;//记录每组的第二个数据下标
                    int j = 0;
                    //从每组第一个数开始
                    for (j = i - d; j >= 0; j -= d) {
                        if (arr[j] > temp) {
                            arr[j + d] = arr[j];
                            flag = j;
                        }
                    }
                    arr[flag] = temp;
                }
            }
        } while (d > 1);    //当d = 1时退出
    }

    //冒泡排序
    private static void bubbleSort(int[] arr) {    //稳定排序算法
        // 一次比较两个元素,如果他们的顺序错误就把他们交换过来

        //大数上浮  j = 0
//        for (int i = arr.length - 1; i > 0; i--)
//            for (int j = 0; j < i; j++)
//                if (arr[j] > arr[j + 1])
//                   swap(arr, j, j + 1);

//        for (int i = 0; i < arr.length - 1; i++)
//            for (int j = 0; j < arr.length - i - 1; j++)
//                if (arr[j] > arr[j + 1])
//                    swap(arr, j, j + 1);
        //整体效果:大数逐渐放到第length位,第length - 1位...。前面一直在从头执行两两比较

        //小数下沉  j = arr.length - 2
//        for (int i = 0; i < arr.length - 1; i++)
//            for (int j = arr.length - 2; j >= i; j--)
//                if (arr[j] > arr[j + 1])
//                    swap(arr, j, j + 1);

        for (int i = arr.length - 1; i > 0; i--)
            for (int j = arr.length - 2; j >= arr.length - 1 - i; j--)
                if (arr[j] > arr[j + 1])
                    swap(arr, j, j + 1);
        //整体效果:小数逐渐放到第1位,第2位...。后面一直在从尾执行两两比较
    }

    //冒泡排序优化
    private static void bubbleSort2(int[] arr) {
        boolean flag = false;   //true代表数组已排好序,false代表数组未排好序
        for (int i = arr.length - 1; i > 0 && flag == false; i--) {
            flag = true;    //默认已排好序
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, arr[j], arr[j + 1]);
                    flag = false;   //只要发生交换,证明该序列未排好序
                    //若某次遍历时已排好序,则直接退出
                }
            }
        }
        //一次比较两个元素,如果他们的顺序错误就把他们交换过来
        //整体效果:大数逐渐放到第length位,第length - 1位...。前面一直在从头执行两两比较
    }

    //快速排序  不稳定
    private static void quickSort(int[] arr, int low, int high) {
        if (low >= high)     //如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了
            return;
        int i = low;  //左指针
        int j = high; //右指针
        int key = arr[low];    //用字表的第一个记录作为枢轴
        while (i < j) {
            while (i < j && arr[j] >= key) {    //只要枢纽右边大于枢纽,j--
                j--;
            }
            arr[i] = arr[j];    //发现右边有小于枢纽的值,就放在i位置
            while (i < j && arr[i] <= key) {   //只要枢纽左边小于枢纽,i++
                i++;
            }
            arr[j] = arr[i];    //发现左边有大于枢纽的值,就放在j位置
        }
        arr[i] = key;   //枢纽到位。此时i == j等于枢纽位置
        quickSort(arr, low, i - 1);
        quickSort(arr, i + 1, high);
        //整体效果,找到每组第一个数作为枢纽,将比该数小的数放左边,大数放右边,再从枢纽两侧进行分组,重复
    }

    //堆排序(最大堆)  不稳定 时间复杂度为O(nlogn);空间复杂度为O(1)
    private static void heapSortMax(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        //初始化堆  结果:堆顶元素最大
        // i = arr.length / 2 - 1 先从最后一个非叶子节点(有孩子的父节点)开始调整
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            heapSwapMax(arr, i, arr.length);
        }
        //排序开始:交换堆顶元素和(堆尾--),交换后(堆尾--)为(最大元素--)
        for (int i = arr.length - 1; i >= 0; i--) {
            swap(arr, 0, i);
            //交换后不符合堆性质,继续从头调整
            heapSwapMax(arr, 0, i);
        }
    }

    //堆调整交换(最大堆)
    private static void heapSwapMax(int[] arr, int index, int len) {
        int max = index;//保存当前父节点下标(默认最大)
        int lChidl = index * 2 + 1;//保存左孩子下标
        int rChidl = index * 2 + 2;//保存右孩子下标
        //在左孩子不为空前提下(不超过长度),如果左孩子大于父节点
        if (lChidl < len && arr[lChidl] > arr[max]) {
            max = lChidl;
        }
        if (rChidl < len && arr[rChidl] > arr[max]) {
            max = rChidl;
        }
        //如果父节点不是最大,就交换节点大的那个孩子,使父节点最大
        if (max != index) {
            swap(arr, index, max);
            //调整后的max位置可能有不符合堆的条件,继续递归调整(max位置现在是孩子位置)
            heapSwapMax(arr, max, len);
        }
    }

    //堆排序(最小堆)
    private static void heapSortMin(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        //初始化堆  结果:堆顶元素最小
        // i = arr.length / 2 - 1 先从最后一个非叶子节点(有孩子的父节点)开始调整
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            heapSwapMin(arr, i, arr.length);
        }
        //排序开始:交换堆顶元素和(堆尾--),交换后(堆尾--)为(最小元素++)
        for (int i = arr.length - 1; i >= 0; i--) {
            swap(arr, 0, i);
            //交换后不符合堆性质,继续从头调整
            heapSwapMin(arr, 0, i);
        }
    }

    //堆调整交换(最小堆)
    private static void heapSwapMin(int[] arr, int index, int len) {
        int min = index;//保存当前父节点下标(默认最小)
        int lChidl = index * 2 + 1;//保存左孩子下标
        int rChidl = index * 2 + 2;//保存右孩子下标
        //在左孩子不为空前提下(不超过长度),如果左孩子小于父节点
        if (lChidl < len && arr[lChidl] < arr[min]) {
            min = lChidl;
        }
        if (rChidl < len && arr[rChidl] < arr[min]) {
            min = rChidl;
        }
        //如果父节点不是最小,就交换节点大的那个孩子,使父节点最小
        if (min != index) {
            swap(arr, index, min);
            //调整后的min位置可能有不符合堆的条件,继续递归调整(min位置现在是孩子位置)
            heapSwapMin(arr, min, len);
        }
    }

    //字符串排序
    private static void stringSort(String[] str) {
        for (int i = str.length - 1; i > 0; i--) {//冒泡
            for (int j = 0; j < i; j++) {
                if (str[j].compareTo(str[j + 1]) > 0) {//若前一个字符串大,前后交换(比较的是每个字符串的首字母)
                    String temp = str[j];
                    str[j] = str[j + 1];
                    str[j + 1] = temp;
                }
            }
        }
    }

    //字符串中的数排序
    private static String stringNumberSort(String numStr) {
        //将字符串变为字符串数组
        String[] str = numStr.split(" +");//对多个空格同样适用(正则表达式)
        //将字符串数组变为int数组
        int[] arr = new int[str.length];
        for (int i = 0; i < str.length; i++) {
            arr[i] = Integer.parseInt(str[i]);
        }
        //排序
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        //将int数组转为字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            sb.append(arr[i]).append(" ");
        }
        return sb.toString();
    }

    //从小到大排序,对一个四位数排序
    private static int intSortMin(int num) {
        int g = num % 10;
        int s = num / 10 % 10;
        int b = num / 100 % 10;
        int q = num / 1000;
        int[] arr = {g, s, b, q};
        Arrays.sort(arr);
        return 1000 * arr[0] + 100 * arr[1] + 10 * arr[2] + arr[3];
    }

    //从大到小排序,对一个四位数排序
    private static int intSortMax(int num) {
        int g = num % 10;
        int s = num / 10 % 10;
        int b = num / 100 % 10;
        int q = num / 1000;
        int[] arr = {g, s, b, q};
        Arrays.sort(arr);
        return 1000 * arr[3] + 100 * arr[2] + 10 * arr[1] + arr[0];
    }

    //数组交换
    private static void swap(int arr[], int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

//字符串按长度排序的比较器
class CompareToByStringLength implements Comparator<String> {
    @Override
    public int compare(String o1, String o2) {
        //如果长度不同,返回字符串内容比较值,如果相同,返回长度比较值
        return (o1.length() - o2.length()) == 0 ? (o1.compareTo(o2)) : (o1.length() - o2.length());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值