代码改变世界

排序算法

  雪夜&流星  阅读(188)  评论(0编辑  收藏  举报

各种排序算法的实现:

复制代码
package com.clarck.datastructure.array;

/**
 * 排序
 * 
 * @author clarck
 *
 */
public class Array {
    /**
     * 输出数组元素
     * @param table
     */
    public static void print(int[] table) {
        if (table != null) {
            for (int i = 0; i < table.length; i++) {
                System.out.print(" " + table[i]);
            }
            System.out.println();
        }
    }
    
    /**
     * 输出对象数组元素
     * @param table
     */
    public static void print(Object[] table) {
        if (table != null) {
            for (int i = 0; i < table.length; i++) {
                System.out.print(" " + table[i].toString());
            }
            System.out.println();
        }
    }
    
    /**
     * 直接插入排序,数组是引用类型,作为方法的参数,其元素值将被改变
     * @param table
     */
    public static void insertSort(int[] table) {
        System.out.println("直接插入排序");
        //n - 1趟扫描
        for (int i = 1; i < table.length; i++) {
            //每趟将table[i]插入到前面排序序列中
            int temp = table[i], j;
            //将签名较大元素向后移动
            for (j = i - 1; j >= 0 && temp < table[j]; j--) {
                table[i + 1] = table[j];
            }
            //temp值到达插入位置
            table[j + 1] = temp;
            System.out.print("第" + i + "趟: ");
            //输出排序中间结果,可省略
            print(table);
        }
    }
    
    /**
     * 希尔排序
     * @param table
     */
    public static void shellSort(int[] table) {
        System.out.println("希尔排序");
        //若干趟扫描,控制增量,增量减半
        for (int delta = table.length / 2; delta > 0; delta /= 2) {
            //一趟分若干组,每组进行直接插入排序
            for (int i = delta; i < table.length; i++) {
                //table[i] 是当前待插入元素
                int temp = table[i], j;
                //每组元素相距delta远,寻找插入位置
                for (j = i - delta; j > 0 && temp < table[j]; j-=delta) {
                    table[j + delta] = table[j];
                }
                table[j + delta] = temp;
            }
            System.out.print("delta=" + delta + " ");
            print(table);
        }
    }
    
    /**
     * 冒泡排序
     * @param table
     */
    public static void bubbleSort(int[] table) {
        System.out.println("冒泡排序");
        //是否交换的标记
        boolean exchange = true;
        
        //有交换是再进行下一趟,最多n-1趟
        for (int i = 1; i < table.length && exchange; i++) {
            //假定元素未交换
            exchange = false;
            //一趟比较、交换
            for (int j = 0; j < table.length - i; j++) {
                if (table[j] > table[j + 1]) {
                    int temp = table[j];
                    table[j] = table[j + 1];
                    table[j + 1] = temp;
                    //有交换
                    exchange = true;
                }
            }
            System.out.print("第" + i + "趟:");
            print(table);
        }
    }
    
    /**
     * 快速排序
     * @param table
     */
    public static void quickSort(int[] table) {
        System.out.println("快速排序");
        quickSort(table, 0, table.length - 1);
    }

    /**
     * 一趟快速排序,begin、high指定序列的下界和上界,递归算法
     * @param table
     * @param begin
     * @param end
     */
    private static void quickSort(int[] table, int begin, int end) {
        //序列有效
        if (begin < end) {
            int i = begin, j = end;
            //第一个值作为基准值
            int vot = table[i];
            //一趟排序
            while (i != j) {
                //从后向前寻找较小值
                while (i < j && vot <= table[j]) {
                    j --;
                }
                
                if (i < j) {
                    //较小元素向前移动
                    table[i++] = table[j];
                }
                
                //从前向后寻找较大值
                while (i < j && table[i] <= vot) {
                    i++;
                }
                
                if (i < j) {
                    //较大元素向后移
                    table[j--] = table[i];
                }
            }
            //基准值到达最终位置
            table[i] = vot;
            System.out.print(begin + ".." + end + ", vot=" + vot + " ");
            print(table);
            //前端子序列再排序,递归调用
            quickSort(table, begin, j - 1);
            //后端子序列再排序,递归调用
            quickSort(table, i + 1, end);
        }
    }
    
    /**
     * 直接选择排序
     * @param table
     */
    public static void selectSort(int[] table) {
        System.out.println("直接选择排序");
        //n - 1趟排序
        //每趟在从i开始的子序列中寻找最小元素
        for (int i = 0; i < table.length - 1; i ++) {
            //设第i个数据元素最小
            int  min = 1;
            for (int j = i + 1; j < table.length; j++) {
                //记住最小元素下标
                if (table[j] < table[min]) {
                    min = j;
                }
            }
            
            //将本趟最小元素交换到前面
            if (min != i) {
                int temp = table[i];
                table[i] = table[min];
                table[min] = temp;
            }
            
            System.out.print("第" + (i + 1) + "趟: ");
            print(table);
        }
    }
    
    /**
     * 堆排序(降序),最小堆
     * @param table
     */
    public static void heapSort_min(int[] table) {
        System.out.println("最小堆?" + isMinHeap(table));
        System.out.println("建立最小堆序列");
        int n = table.length;
        for (int j = n / 2 - 1; j >= 0; j++) {
            sift_min(table, j, n - 1);
        }
        System.out.println("最小堆?" + isMinHeap(table));
        System.out.println("堆排序(降序)");
        
        //每趟将最小值交换到后面,再调整成堆
        for (int j = n - 1; j > 0; j--) {
            int temp = table[0];
            table[0] = table[j];
            table[j] = temp;
            sift_min(table, 0, j - 1);
        }
    }

    /**
     * 将以begin为根的子树调整成最小堆,begin、end是序列下界和上界
     * @param table
     * @param j
     * @param i
     */
    private static void sift_min(int[] table, int begin, int end) {
        //i为子树的根,j为i结点的左孩子
        int i = begin, j = 2 * i + 1;
        //获得第i个元素的值
        int temp = table[i];
        //沿较小值孩子结点向下筛选
        while (j <= end) {
            //数组元素比较(改成<为最大堆)
            if (j < end && table[j] > table[j + 1]) {
                //j为左右孩子的较小者
                j ++;
            }
            //若父母结点值较大(改成<为最大堆)
            if (temp > table[j]) {
                //孩子结点中的较小值上移
                table[i] = table[j];
                i = j;
                j = 2 * j + 1;
            } else {
                break;
            }
        }
        //当前子树的原根值调整后的位置
        table[i] = temp;
        System.out.print("sift " + begin + ".." + end + " ");
        print(table);
    }
    
    /**
     * 堆排序(升序),最大堆
     * @param table
     */
    public static void heapSort_max(int[] table) {
        System.out.println("最大堆?" + isMaxHeap(table));
        System.out.println("建立最大堆序列");
        int n = table.length;
        for (int j = n / 2 - 1; j >= 0; j--) {
            sift_max(table, j, n - 1);
        }
        System.out.println("最大堆?" + isMaxHeap(table));
        System.out.println("堆排序(升序)");
        
        //每趟将最大值交换到后面,再调整成堆
        for (int j = n - 1; j > 0; j --) {
            int temp = table[0];
            table[0] = table[j];
            table[j] = temp;
            sift_max(table, 0, j - 1);
        }
    }

    /**
     * 将以begin为根的子树调整成最大堆,begin、end是序列下界和上界
     * @param table
     * @param begin
     * @param end
     */
    private static void sift_max(int[] table, int begin, int end) {
        //i为子树的根,j为i结点的左孩子
        int i = begin, j = 2 * i + 1;
        //获得第i个元素的值
        int temp = table[i];
        //沿较大值孩子结点向下筛选
        while (j <= end) {
            //数组元素比较
            if (j < end && table[j] < table[j + 1]) {
                j ++;
            }
            
            //若父母结点值较小
            if (temp < table[j]) {
                table[i] = table[j];
                i = j;
                j = 2 * i + 1;
            } else {
                break;
            }
        }
        //当前子树的原根值调整后的位置
        table[i] = temp;
        System.out.print("sift " + begin + ".." + end + " ");
        print(table);
    }
    
    /**
     * 归并排序
     * @param x
     */
    public static void mergeSort(int[] X) {
        System.out.println("归并排序");
        //Y数组长度同X数组
        int[] Y = new int[X.length];
        //已排序的子序列长度,初值为1
        int n = 1;
        while (n < X.length) {
            //一趟归并,将X书中中各子序列归并到Y中
            mergepass(X, Y, n);
            print(Y);
            //子序列长度加倍
            n *= 2;
            
            if (n < X.length) {
                //将Y书中各子序列再归并到X中
                mergepass(X, Y, n);
                print(X);
                n *= 2;
            }
        }
    }

    /**
     * 一趟归并
     * @param x
     * @param y
     * @param n
     */
    private static void mergepass(int[] X, int[] Y, int n) {
        System.out.print("子序列长度n=" + n + " ");
        int i = 0;
        //X中若干相邻子序列归并到Y中
        for (i = 0; i < X.length - 2 * n + 1; i += 2 * n) {
            //将X中两个相邻子序列一次归并到Y数组中
            merge(X, Y, i, i + n, n);
        }
        
        if (i + n < X.length) {
            merge(X, Y, i, i + n, n);
        } else {
            //将X剩余元素复制到Y中
            for (int j = i; j < X.length; j++) {
                Y[j] = X[j];
            }
        }
    }

    /**
     * 一次归并
     * @param X
     * @param Y
     * @param m
     * @param r
     * @param n
     */
    private static void merge(int[] X, int[] Y, int m, int r, int n) {
        int i = m, j = r, k = m;
        //将X中两个相邻子序列归并到Y中
        while (i < r && j < r + n && j < X.length) {
            //较小值复制到Y中
            if (X[i] < X[j]) {
                Y[k++] = X[i++];
            } else {
                Y[k++] = X[j++];
            }
        }
        
        //将前一个子序列剩余元素复制到Y中
        while (i < r) {
            Y[k++] = X[i++];
        }
        
        //将后一个子序列剩余元素复制到Y中
        while (j < r + n && j < X.length) {
            Y[k++] = X[j++];
        }
    }
    
    /**
     * 对象数组的直接插入排序
     * @param value
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void insertSort(Comparable[] value) {
        System.out.println("直接插入排序");
        //n - 1趟扫描
        for (int i = 1;i < value.length; i++) {
            //每趟将value[i]插入到签名排序子序列中
            Comparable temp  = value[i];
            int j;
            //将前面较大元素向后移动
            for (j = i - 1; j >= 0 && temp.compareTo(value[j]) < 0; j--) {
                value[j + 1] = value[j];
            }
            value[j + 1] = temp;
            
            System.out.print("第" + i + "趟");
            //调用print(Object) 输出排序中间结果,可省略
            print(value);
        }
    }

    /**
     * 判断一个数据序列是否为最大堆
     * @param value
     * @return
     */
    private static boolean isMaxHeap(int[] value) {
        //空序列不是堆
        if (value.length == 0) {
            return false;
        }
        
        //i聪最深一棵子树的根结点开始
        for (int i = value.length / 2 - 1; i >= 0; i--) {
            int j = 2 * i + 1;
            if (value[i] < value[j] || j + 1 < value.length && value[i] < value[j + 1]) {
                return false;
            }
        }
        
        return true;
    }

    /**
     * 判断一个数据序列是否为最小堆
     * @param table
     * @return
     */
    private static boolean isMinHeap(int[] value) {
        //空序列不是堆,若无此句,则空序列是堆,定义不同
        if (value.length == 0) {
            return false;
        }
        //i从最深一棵子树的根结点开始
        for (int i = value.length / 2 - 1; i >= 0; i--) {
            //j 是i的左孩子,肯定存在
            int j = 2 * i + 1;
            if (value[i] > value[j] || j + 1 < value.length && value[i] > value[j + 1])
                return false;
        }
        return true;
    }
}
复制代码

测试类:

复制代码
package com.clarck.datastructure.array;

/**
 * 随即数序列的直接插入排序
 * 
 * @author clarck
 *
 */
public class Array_test {
    //产生n个随机数,返回整型数组
    public static int[] random(int n) {
        if (n <= 0) {
            return null;
        }
        
        int table[] = new int[n];
        for (int i = 0; i < table.length; i++) {
            //产生一个0~99之间的随机数
            table[i] = (int) (Math.random() * 100);
        }
        return table;
    }
    
    public static void main(String[] args) {
//        int[] table = {32,26,87,72,26,17};                 //直接插入排序图9-1
        int[] table = Array_test.random(9);   
//      int[] table = {27,38,65,97,76,13,27,49,55,4};      //9.2.2希尔排序图9-2
           
//        int[] table = {32,26,87,72,26,17};                 //冒泡排序,图9-2
//        int[] table = {1,2,3,4,5,6,7,8};                   //冒泡排序,快速排序,最小堆
//        int[] table = {1,3,2,4,5,8,6,7};                   //冒泡排序
//        int[] table = {4,5,8,1,2,7,3,6};                   //冒泡排序
//        int[] table = {8,7,6,5,4,3,2,1};                   //冒泡排序,快速排序
//        int[] table = {38,26,97,19,66,1,5,49};             //快速排序 ,图9-5
//        int[] table = {38,97,26,19,38,5};                  //直接选择排序,图9-7
//        int[] table = {81,49,38,27,97,76,19,13};           //堆排序,图9-9
//        int[] table = {36,74,68,61,55,15,4,12};        //堆排序
//        int[] table = {52,26,97,19,66,8,49};               //归并排序,图9-11

        //        int[] table = {49,65,13,81,76,97,38,49};
//      int[] table = {85,12,36,24,47,30,53,91,76};
        System.out.print("关键字序列: ");
        Array.print(table);
//        Array.insertSort(table);
//        Array.shellSort(table);
//        Array.bubbleSort(table);
//        Array.quickSort(table);
//        Array.selectSort(table);
//        Array.heapSort_min(table);
//        Array.heapSort_max(table);
        Array.mergeSort(table);

//      int[] table = {13,27,38,49,97,76,49,81};        //最小堆
//        int[] table = {9,13,62,69,76,92,96,72,96};        //最小堆
//        int[] table = {9,13,62,59,26,92,56,72,96};        //不是最小堆
//        System.out.println("最小堆序列? "+Array.isMinHeap(table));
//        int[] table = {94,85,74,58,7,20,60,26,35};        //最大堆
//        int[] table = {94,85,34,58,7,20,60,26,35};        //不是最大堆
//      int[] table = {97,81,38,76,49,27,19,13,65};        //最大堆
//        System.out.println("最大堆序列? "+Array.isMaxHeap(table));
    }
}
复制代码

 

编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示