Java 常见的几种排序--冒泡排序、选择排序、插入排序、快速排序、归并排序、基数排序、希尔排序

冒泡排序

    // 冒泡排序
    public static void bubbleSort(int[] arr){
        // flag作为冒泡排序的优化
        // 标识是否交换过数据,如果一次冒泡都没有交换数据,则说明以及有序,直接退出
        boolean flag = false; 
        for(int i = 0; i < arr.length - 1; i++){
            for(int j = 0; j < arr.length - 1 - i; j++){
                if(arr[j] > arr[j + 1]){
                    flag = true;    // 交换过数据
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            // 没有交换过数据,直接退出
            if(!flag){
                break;
            }else{
                // 重置flag进行下一次判断
                flag = false; 
            }
        }
        
    }

选择排序 

    // 选择排序 -- 选择最小的放在前面
    public static void selectSort(int[] arr){
        for(int i=0; i<arr.length; i++){
            // 假设第i位是最小的
            int minIndex = i;  
            int minVal = arr[i];
            // 遍历后面的元素, 如果有比第i为更小的,则更新最小位
            for(int j=i+1; j<arr.length; j++){
                if(minVal > arr[j]){
                    minIndex = j;   // 更新最小值索引
                    minVal = arr[j]; // 更新最小值
                }
            }
            // 如果最小位的所要更新过,则需要交换数据
            if(minIndex != i){
                arr[minIndex] = arr[i];
                arr[i] = minVal;
            }
        }
    }

插入排序

    // 插入排序
    // 将待排序的元素分为有序表和无序表,一开始默认有序表只有第一位元素
    // 将无序表的元素插入到有序表中 -- 判断大小需要插入的位置,然后插入
    public static void insertSort(int[] arr){
        for(int i=1; i<arr.length; i++){    // 无序表从第二个原始开始
            int insertIndex = i-1;    // 插入的位置,初始化为前一位
            int insertVal = arr[i];  // 要插入的元素
            
            // 插入的位置要小于0,确认没有越界
            // insertVal < arr[insertIndex] 则没有找到合适的位置,需要继续往前走
            while(insertIndex >= 0 && insertVal < arr[insertIndex]){
                // 数值后移 -- 事先保持了要插入的元素 insertVal
                arr[insertIndex+1] = arr[insertIndex];  
                insertIndex--;  // 索引前移
            }
            // 索引是否发送改变,如果没有改变,则不需要交换数据
            if(insertIndex != i-1){
                arr[insertIndex+1] = insertVal;
            }
        }
    }

快速排序

    //快速排序 -- 一趟排序将元素分成两部分,一部分小于另一部分
    public static void quickSort(int[] arr, int left, int right){
        if(left > right){
            return;
        }
        int l = left;   // 左边界
        int r = right;  // 有边界
        int val = arr[left]; // 自定义的 一趟排序完成后的分界值
        while(l < r){
            // 以下两个while循环执行顺序不能变,
            while(val <= arr[r] && l < r) r--;  // 从右边开始找一个比分界值小的数
            while(val >= arr[l] && l < r) l++;  // 再从左边开始找一个比分界值大的数
            // 交换数据
            if(l < r){
                int temp = arr[r];
                arr[r] = arr[l];
                arr[l] = temp;
            }
        }
        // 退出循环时,l=r, arr[l] 与 分解值 val 进行交换
        // 如果先从右边开始找比分界值大的数,arr[l]的值小于分界值 √
        // 如果先从左边开始找比分界值大的数,arr[l]的值大于分界值 ×
        // 如果arr[l]大于分界值,交换之后,左边部分不会全部小于右边,不会有序
        
        // 交换数据 -- 将分界值val放到中间
        arr[left] = arr[l];  
        arr[l] = val;    
        // 先左递归
        quickSort(arr, left, l-1);
        // 先右递归
        quickSort(arr, l+1, right);
    }

归并排序

    // 归并排序 -- 分治思想 需要额外的数组空间 temp
    public static void mergeSort(int[] arr, int left, int right, int[] temp){
        if(left < right){
            int mid = (left + right) / 2;     //中间索引
            mergeSort(arr, left, mid, temp);  // 左递归分解
            mergeSort(arr, mid+1, right, temp); // 右递归分解
            merge(arr, left, mid, right, temp); // 排序
        }
    }
    // 归并排序
    public static void merge(int[] arr, int left, int mid, int right, int[] temp){
        int i=0;  // 作为temp的索引
        int l1 = left; // 左边序列的起始索引
        int l2 = mid+1; // 右边序列的起始索引
        while(l1 <= mid && l2 <= right){
            if(arr[l1] < arr[l2]){  // 如果左边序列的数小于右边序列
                temp[i++] = arr[l1++]; // 将左边序列的数加入到temp辅助数组中
            }else{
                temp[i++] = arr[l2++];
            }
        }
        // 将剩下的数据全部加入的temp中
        while(l1 <= mid){
            temp[i++] = arr[l1++];
        }
        while(l2 <= right){
            temp[i++] = arr[l2++];
        }
        // 将temp中的值重新赋值为arr
        for(int t=0; t<i; t++){
			arr[left+t] = temp[t];
        }
    }

基数排序 -- 桶排序

    //基数排序 -- 桶排序
    // 根据元素的个、十、百、千位的数值进行排序
    public static void bucketSort(int[] arr){
        // 找出最大的位数,确认需要进行多少次循环
        int maxLength = 0;
        for(int k : arr){
            if((k + "").length() > maxLength){
                maxLength = (k + "").length();
            }
        }
        // 定义一个二维数组 
        // 行 -- 10个桶 0 ~ 9 代表某位的数值
        // 列 -- 元素的个数,可能存在极端情况--所有元素的某一位的数值相同
        int[][] bucket = new int[10][arr.length];
        // 定义一个一维数组,保存每个桶中有多少值,后面需要从中取出
        int[] bucketCount = new int[10];
        // 加入到桶里面
        for(int i=0, n=1; i<maxLength; i++, n*=10){
            for(int j=0; j<arr.length; j++){
                // 先整除,后取余数,获取每一位的数值
                int index = arr[j] / n % 10;   
                // 加入到对应的桶中
                // bucketCount[index] 表示该桶的第二个数据
                bucket[index][bucketCount[index]] = arr[j];
                // 该桶的数量加一
                bucketCount[index]++;
            }
            int index = 0;  // arr 的索引
            // 取出数据
            for(int k=0; k<bucketCount.length; k++){
                // 不是所有的桶都有数据
                if(bucketCount[k] != 0){ 
                    // 从头循环该桶取出数据
                    for(int m=0; m<bucketCount[k]; m++){
                        arr[index++] = bucket[k][m];
                    }
                }
                // 清空记录
                bucketCount[k] = 0;
            }
        }
    }

希尔排序 -- 交换法、移位法

    // 希尔排序 -- 交换法
    public static void shellSort(int[] arr){
        // 分组
        for(int gap = arr.length/2; gap > 0; gap /= 2){
            // 遍历每组的元素
            for(int i = gap; i<arr.length; i++){
                // 每组的元素进行比较交换
                for(int j = i-gap; j >= 0; j -= gap){
                    if(arr[j] > arr[j + gap]){
                        int temp = arr[j];
                        arr[j] = arr[j + gap];
                        arr[j+gap] = temp;
                    }
                }
            }
        }
    }
    // 希尔排序 -- 移位法 -- 效率更高
    public static void shellSort2(int[] arr){
        // 分组
        for(int gap = arr.length/2; gap > 0; gap /= 2){
            // 遍历每组的元素
            for(int i = gap; i<arr.length; i++){
                // 从gap元素开始对该组元素直接进行插入排序
                int insertIndex = i - gap;
                int insertVal = arr[i];
                while(insertIndex >= 0 && insertVal <= arr[insertIndex]){
                    arr[insertIndex + gap] = arr[insertIndex];
                    insertIndex -= gap;
                }
                // 判断是否移动过
                if(insertIndex != i - gap){
                    arr[insertIndex + gap] = insertVal;
                }
            }
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值