• 排序算法(1)-冒泡排序,选择排序,插入排序,希尔排序,快速排序


    一些基本的排序算法:

    package tenSortingMethods;
    /**
     * @author zhangdi
     * @description 排序算法
     * @Date 20180531
     */
    public class Sort {
    
        public static void main(String[] args) {
            int[] arr = {6,1,2,7,9,3,4,5,10,8};//{ 26, 88, 45, 57, 12, 31, 12, 2, 64, 32, 20, 99, 1 };
            int[] arr1 = { 2, 1, 3, 5, 4 };// {6,1,2,7,9,3,4,5,10,8};
    
            // System.out.println(arr.getClass());
            System.out.println(" arr before sorting: " + IntArrtoString(arr));
            // BubbleSort(arr);
            // BubbleSort2(arr);
            // BubbleSort1_better(arr);
            // SelectSort(arr);
            // InsertionSort(arr);
            // ShellSort(arr);
            // ShellSort2(arr);
    
            // int[] quickSort = new Sort().QuickSort(arr, 0, arr.length - 1);
            // System.out.println(" quickSort after sorting: " +
            // IntArrtoString(quickSort));
    
    
             int[] quickSort2 = new Sort().QuickSort2(arr, 0, 9);
            // System.out.println(" quickSort2 after sorting: " +
            // IntArrtoString(quickSort2));
    
             System.out.println(" arr after sorting: " + IntArrtoString(arr));
    
        }
    
        /**
         * @description 冒泡排序
         * @param arr
         * @description : 两两比较,大的往后放; 每一次比较完成之后,下一次就少比较一个元素
         *              第一次比较有0个元素不比较;第二次有一个元素不需要比较;第三次有两个元素不需要比较;
         *              共需要比较arr.length-1次
         */
        public static void BubbleSort(int[] arr) {
    
            int temp;// 临时变量
            if (arr == null || arr.length == 0)
                return;
            for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
                for (int j = arr.length - 1; j > i; j--) {
    
                    if (arr[j] < arr[j - 1]) {
                        temp = arr[j];
                        arr[j] = arr[j - 1];
                        arr[j - 1] = temp;
                    }
                }
            }
        }
    
        /**
         * @description 冒泡排序-2
         * @param arr
         * 
         */
        public static void BubbleSort2(int[] arr) {
    
            int temp;// 临时变量
            if (arr == null || arr.length == 0)
                return;
            for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
                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;
                    }
                }
            }
        }
    
        /**
         * @description 冒泡排序-1-优化
         * @param arr
         *            * 针对问题:数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。
         *            方案: 设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
         *            这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
         * 
         */
        public static void BubbleSort1_better(int[] arr) {
    
            int temp;// 临时变量
            boolean flag;
            if (arr == null || arr.length == 0)
                return;
            for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
                flag = false;
                for (int j = arr.length - 1; j > i; j--) {
                    if (arr[j] < arr[j - 1]) {
                        temp = arr[j];
                        arr[j] = arr[j - 1];
                        arr[j - 1] = temp;
                    }
                }
                if (!flag)
                    break;
            }
        }
    
        /**
         * @description 选择排序
         * @param arr
         *            在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
         *            第二次遍历n-2个数,找到最小的数值与第二个元素交换; 。。。
         *            第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。
         */
        public static void SelectSort(int[] arr) {
            int len = arr.length;
            int temp;// 临时变量
            if (arr == null || len == 0)
                return;
            for (int i = 0; i < len - 1; i++) {
                int minIndex = i;// 假定此时i位置元素为最小数值
                for (int j = i + 1; j < arr.length; j++) {
                    if (arr[j] < arr[minIndex]) {
                        // 如果i+1后的元素值小于i位置的元素,那么改变minIndex值.当内层循环走完,此时数组最小值得小标就确定了
                        minIndex = j;
                    }
                }
                if (minIndex != i) {
                    // 最小值下标改变,交换元素
                    temp = arr[i];
                    arr[i] = arr[minIndex];
                    arr[minIndex] = temp;
                }
            }
        }
    
        /**
         * @description 插入排序
         * @param arr
         * @description : 在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。
         *              如此反复循环,直到全部排好顺序。 位于表中后面的元素依次与表中前面的元素比较,若比之小,则还需继续和更前面的元素比较,
         *              直至遇到一个比它大的元素或者比较到第一个元素(哨兵)了。
         */
        public static void InsertionSort(int[] arr) {
            int len = arr.length;
            int temp;// 临时变量
            if (arr == null || len == 0)
                return;
            for (int i = 0; i < len - 1; i++) {// 趟数n-1趟
                for (int j = i + 1; j > 0; j--) {
                    if (arr[j] < arr[j - 1]) {
                        temp = arr[j];
                        arr[j] = arr[j - 1];
                        arr[j - 1] = temp;
                    } else {
                        break;
                    }
                }
            }
        }
    
        /**
         * @description 希尔排序 (最小增量排序)
         * @param arr
         * @description: 我们选择增量gap=length/2,缩小增量继续以gap =
         *               gap/2的方式,这种增量选择我们可以用一个序列来表示,{n /2,(n/2)/2...1},称为增量序列。
         *               希尔排序的增量序列的选择与证明是个数学难题, 我们选择的这个增量序列是比较常用的,也是希尔建议的增量,
         *               称为希尔增量,但其实这个增量序列不是最优的。 此处我们做示例使用希尔增量。
         *               比如原始数组8917235460,初始增量为gap =length/5;即数组被分为五组
         *               [8,3],[9,5],[1,4],[7,6],[2,0] ,对五组分别进行插入排序;第一次排序后:
         *               3514089472,缩小增量为gap =gap/2 =
         *               2;分为两组[3,5,1,4,0],[8,9,4,7,2],插入排序 -->[0214357698],
         *               再缩小增量gap = gap/ = 1,[0214357698] -->插入排序.
         * 
         * 
         */
        public static void ShellSort(int[] array) {
            int temp = 0;
            int incre = array.length;
            while (true) {
                incre = incre / 2;
                for (int k = 0; k < incre; k++) { // 根据增量分为若干子序列
                    for (int i = k + incre; i < array.length; i += incre) {
                        for (int j = i; j > k; j -= incre) {
                            if (array[j] < array[j - incre]) {
                                temp = array[j - incre];
                                array[j - incre] = array[j];
                                array[j] = temp;
                            } else {
                                break;
                            }
                        }
                    }
                }
    
                if (incre == 1) {
                    break;
                }
            }
        }
    
        /**
         * @description 希尔排序 (最小增量排序)
         * @param arr
         *            在希尔排序的理解时,我们倾向于对于每一个分组,逐组进行处理,但在代码实现中,
         *            我们可以不用这么按部就班地处理完一组再调转回来处理下一组( 这样还得加个for循环去处理分组)比如[5,4,3,2,1,0]
         *            ,首次增量设gap=length/2=3,则为3组[5,2] [4,1]
         *            [3,0],实现时不用循环按组处理,我们可以从第gap个元素开始,逐个跨组处理。同时,在插入数据时,
         *            可以采用元素交换法寻找最终位置, 也可以采用数组元素移动法寻觅。
         * 
         */
        /**
         * 希尔排序 针对有序序列在插入时采用交换法 见图
         * 
         * @param arr
         */
        public static void ShellSort2(int[] arr) {
            System.out.println("ShellSort2 start.........");
            // 增量gap,并逐步缩小增量
            for (int gap = arr.length / 2; gap > 0; gap /= 2) {
                // 从第gap个元素,逐个对其所在组进行直接插入排序操作
                System.out.println("1 gap:" + gap + "  arr:" + IntArrtoString(arr));
                for (int i = gap; i < arr.length; i++) {
    
                    int j = i;
                    while (j - gap >= 0 && arr[j] < arr[j - gap]) {
                        // 插入排序采用交换法
                        swap(arr, j, j - gap);
                        j -= gap;
                    }
                    System.out.println("2 gap:" + gap + " i:" + i + " arr:" + IntArrtoString(arr));
                }
            }
            System.out.println("ShellSort2 end...........");
        }
    
        /**
         * 希尔排序 针对有序序列在插入时采用移动法。
         * 
         * @param arr
         */
        public static void ShellSort3(int[] arr) {
            // 增量gap,并逐步缩小增量
            for (int gap = arr.length / 2; gap > 0; gap /= 2) {
                // 从第gap个元素,逐个对其所在组进行直接插入排序操作
                for (int i = gap; i < arr.length; i++) {
                    int j = i;
                    int temp = arr[j];
                    if (arr[j] < arr[j - gap]) {
                        while (j - gap >= 0 && temp < arr[j - gap]) {
                            // 移动法
                            arr[j] = arr[j - gap];
                            j -= gap;
                        }
                        arr[j] = temp;
                    }
                }
            }
        }
    
        /**
         * 交换数组元素
         * 
         * @param arr
         * @param a
         * @param b
         */
        public static void swap(int[] arr, int a, int b) {
            arr[a] = arr[a] + arr[b];
            arr[b] = arr[a] - arr[b];
            arr[a] = arr[a] - arr[b];
        }
    
        /**
         * @param arr
         * @description 快速排序 基本思想:(分治) 先从数列中取出一个数作为key值;
         *              将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边; 对左右两个小数列重复第二步,直至各区间只有1个数。
         * @ses http://developer.51cto.com/art/201403/430986.htm
         *      https://blog.csdn.net/morewindows/article/details/6684558
         */
        // 快速排序
        public int[] QuickSort(int[] a, int l, int r) {
    
            if (l < r) {
                int i = l, j = r, v = a[l];// i:左边开始活动坐标,j:右边开始活动坐标,v:基数,用于对比的值,一般取第一个
                while (i < j) {// 只要左边游标和游标不重叠的话那么就继续遍历
                    System.out.println("i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                    // 每一轮遍历的时候只进行一轮,把右边的一个比基数小的数移动到左边,把左边比基数大的数移动到右边
                    while (i < j && a[j] > v)
                        // 找出右边比左边小的坐标
                        j--;
                    if (i < j)
                        a[i++] = a[j];// 进行移动,左边坐标移动一个数
                    System.out.println("i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                    while (i < j && a[i] < v)
                        // 找出左边比右边大的坐标
                        i++;
                    if (i < j)
                        a[j--] = a[i];// 进行移动,右边坐标移动一个数
                    System.out.println("i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                }
                a[i] = v;// 当游标重叠时填入基数
                this.QuickSort(a, l, i - 1);
                this.QuickSort(a, i + 1, r);
                return a;
            }
            return a;
        }
    
        /**
         * @param a
         * @param left
         * @param right
         * @return  QuickSort2在一轮对比基准数的过程中不移动基准数,减少移动次数
         */
        public int[] QuickSort2(int[] a, int left, int right) {
            //校验要初始化变量之前;不校验易报错:java.lang.ArrayIndexOutOfBoundsException
            if (left>right ) {
                return a;
            }
            int i = left, j = right, s = a[left];
            int temp;
    
            while (i < j) {
                //System.out.println("1--------i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                while (a[j] >= s && j > i) {
                    j--;
                    //System.out.println("2--------i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                }
                while (a[i] <= s && j > i) {
                    i++;
                    //System.out.println("3--------i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                }
                if (i < j) {
                    temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                    //System.out.println("4---------i:" + i + " j:" + j + " arr:" + IntArrtoString(a));
                }
            }
            a[left] = a[i];
            a[i] = s;
    
            QuickSort2(a, left, i - 1);
            QuickSort2(a, i + 1, right);
            return a;
    
        }
    
    
    
    }
    
  • 相关阅读:
    ReentrantLock的实现原理
    Dubbo服务治理
    AQS原理
    flink写es性能优化
    spring的事务机制
    星形模型和雪花模型的区别
    关于使用云服务器做广域网通讯测试的资料整理
    pycharm 远程连接
    日记 2022.04.20
    《时间简史》 初读后感
  • 原文地址:https://www.cnblogs.com/DiZhang/p/12545017.html
Copyright © 2020-2023  润新知