Top 10 Sorting Algorithms.

冒泡排序(Bubble Sort)

通过相邻元素的比较和交换来进行排序。

 public class BubbleSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length == 0) return nums;
        for (int i = 0; i < nums.length; i++) {
            // [nums.length - 1 - i ]  最后一个数据已经排序完了
            for (int j = 0; j < nums.length - 1 - i; j++) {
                if (nums[j] > nums[j + 1]) {
                    int temp = nums[j + 1];
                    nums[j + 1] = nums[j];
                    nums[j] = temp;
                }
                System.out.println(Arrays.toString(nums));
            }
            System.out.println("----------------------------------");
        }
        return nums;
    }
}

选择排序(Selection Sort)

每次从未排序的部分中选择最小(或最大)的元素放到已排序部分的末尾。

  public class ChooseSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length == 0) return nums;
        for (int i = 0; i < nums.length; i++) {
            int minIndex = i;//最小值下标
            for (int j = i; j < nums.length; j++) {
                if (nums[j] < nums[minIndex]) {
                    minIndex = j;
                }
            }

            System.out.println("最小数为:" + nums[minIndex]);

            int temp = nums[i];
            nums[i] = nums[minIndex];
            nums[minIndex] = temp;
            System.out.println(Arrays.toString(nums));
            System.out.println("---------------------------");
        }
        return nums;
    }
}

插入排序(Insertion Sort)

将元素逐个插入到已排序的部分中的正确位置。

   public class InsertSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length == 0) return nums;
        int currentValue;
        for (int i = 0; i < nums.length - 1; i++) {
            int preIndex = i;
            currentValue = nums[preIndex + 1];
            System.out.println("待排序元素索引:" + (i + 1) + " 值为:" + currentValue + ",已经被排序数组的索引: " + preIndex);
            /*在已被排序过的数据中倒序寻找合适的位置,如果当前待排序数据比比较的数据小,讲比较的数据的元素后移一位*/
            while (preIndex >= 0 && currentValue < nums[preIndex]) {
                nums[preIndex + 1] = nums[preIndex];
                preIndex--;
                System.out.println(Arrays.toString(nums));
            }
            /*while循环结束时,说明已经找到了当前待排序数据的合适位置,插入*/
            nums[preIndex + 1] = currentValue;
            System.out.println("本轮被插入排序后的数组");
            System.out.println(Arrays.toString(nums));
            System.out.println("----------------------");

        }
        return nums;
    }
}

快速排序(Quick Sort)

通过选择一个基准元素,将数组分割为左右两部分,然后递归地对两部分进行排序。

public class QuickSort {
    public static void sortArray(int[] nums) {
        sort(nums, 0, nums.length - 1);
        System.out.println(Arrays.toString(nums));
    }

    private static void sort(int[] nums, int low, int high) {
        if (low >= high) return;
        int left = low;
        int right = high;
        int pivot = nums[low];
        while (left < right) {
            while (left < right && nums[right] >= pivot) {
                right--;
            }
            while (left < right && nums[left] <= pivot) {
                left++;
            }
            if (left < right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
            }
        }

        //left==right
        nums[low] = nums[left];
        nums[left] = pivot;

        sort(nums, low, left - 1);
        sort(nums, left + 1, high);
    }
}

归并排序(Merge Sort)

将数组递归地分割为两个子数组,然后将两个有序子数组合并为一个有序数组。

public class MergeSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length < 2) return nums;
        int mid = nums.length / 2;
        int[] left = Arrays.copyOfRange(nums, 0, mid);
        int[] right = Arrays.copyOfRange(nums, mid, nums.length);
        return merger(sortArray(left), sortArray(right));
    }

    private static int[] merger(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        int indexLeft = 0, indexRight = 0;
        for (int i = 0; i < result.length; i++) {
            if (indexLeft >= left.length) { /*左边数组已经取完了,直接取右边即可*/
                result[i] = right[indexRight++];
            } else if (indexRight >= right.length) { /*右边数组已经取完了,直接取左边即可*/
                result[i] = left[indexLeft++];
            } else if (left[indexLeft] > right[indexRight]) { /*左边数组的元素值大于右边数组的值,取右边*/
                result[i] = right[indexRight++];
            } else {/*右边数组的元素值大于左边数组的值,取左边*/
                result[i] = left[indexLeft++];
            }
        }
        System.out.println("左子数组: " + Arrays.toString(left));
        System.out.println("右子数组: " + Arrays.toString(right));
        System.out.println("合并后数组: " + Arrays.toString(result));
        System.out.println("--------------------------------");
        return result;
    }
}

堆排序(Heap Sort)

通过构建最大堆或最小堆来进行排序。


public class HeapSort {
    //声明全局变量,用于记录数组Array的长度
    private static int len;

    public static int[] sortArray(int[] nums) {
        len = nums.length;
        if (len < 1) return nums;
        /*1.构建一个最大堆*/
        buildMaxHeap(nums);
        /*2.循环将堆首位(最大值)与未排序数据末位交换,然后重新调整最大堆*/
        while (len > 0) {
            swap(nums, 0, len - 1);
            len--;
            adjustHeap(nums, 0);
            System.out.println(Arrays.toString(nums));
            System.out.println("-------------------");
        }
        return nums;
    }

    private static void buildMaxHeap(int[] nums) {
        /*从最后一个非叶子节点开始向上构建最大堆*/
        /* 对于完全二叉树: 最后一个非叶子节点的位置为  (n/2)-1, n为数组长度  */
        for (int i = len / 2 - 1; i > 0; i--) {
            adjustHeap(nums, i);
        }
        System.out.println("构造完成最大堆");
        System.out.println(Arrays.toString(nums));
        System.out.println("====================");
    }

    private static void adjustHeap(int[] array, int i) {
        int maxIndex = i;
        /*  对于完全二叉树:左子节点位置= 2*k+1  , 右子节点位置= 2*(k+1)  */
        int left = 2 * i + 1;
        int right = 2 * (i + 1);

        /*  如果有左子树,且左子树大于父节点,则将最大指针指向左子树  */
        if (left < len && array[left] > array[maxIndex]) {
            maxIndex = left;
        }
        /*  如果有右子树,且右子树大于父节点且大于左子树,则将最大指针指向右子树  */
        if (right < len && array[right] > array[maxIndex] && array[right] > array[left]) {
            maxIndex = right;
        }
        if (maxIndex != i) {
            swap(array, maxIndex, i);
            System.out.println(Arrays.toString(array));
            //因为有数据交换,所以继续递归调整
            adjustHeap(array, maxIndex);
        }
    }


    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

希尔排序(Shell Sort)

将数组分割为多个子序列,对每个子序列进行插入排序,然后逐步缩小子序列的间隔,最终进行一次插入排序。

public class ShellSort {
    public static int[] sortArray(int[] nums) {
        int len = nums.length;
        /*按增量分组后,每个分组中,temp代表当前待排序的数据,该元素之前的组内元素均已被排序过*/
        /*grp指用来分组的增量,会依次递减*/
        int currentValue, grp = len / 2;
        while (grp > 0) {
            for (int i = grp; i < len; i++) {
                currentValue = nums[i];
                /*组内已被排序数据的索引*/
                int preIndex = i - grp;
                /*在组内已被排序过数据中倒序寻找合适的位置,如果当前待排序数据比比较的元素要小,则将比较元素在组内后移一位*/
                while (preIndex >= 0 && nums[preIndex] > currentValue) {
                    nums[preIndex + grp] = nums[preIndex];
                    preIndex -= grp;
                }
                /*while循环结束时,说明已经找到了当前待排序数据的合适位置,插入*/
                nums[preIndex + grp] = currentValue;
            }
            System.out.println("本轮增量" + "[" + grp + "]" + "排序后的数组");
            System.out.println(Arrays.toString(nums));
            System.out.println("-----------------------------------");
            grp /= 2;
        }
        return nums;
    }
}

计数排序(Counting Sort)

通过统计每个元素出现的次数,然后根据统计结果进行排序。

public class CountingSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length == 0) return nums;
        /*寻找数组中最大值和最小值,
         * bias:偏移量,用来定位 原始数组 每个元素在 计数数组 中的下标位置*/
        int bias, min = nums[0], max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            max = Math.max(nums[i], max);
            min = Math.min(nums[i], min);
        }
        bias = -min;
        /*初始化计数数组  (max-min+1) 为容量大小*/
        int[] counterArray = new int[max - min + 1];
        /*遍历整个原始数组,将原始数组中每个元素值转化为计数数组下标,并将计数数组下标对应的元素值大小进行累加*/
        for (int i = 0; i < nums.length; i++) {
            counterArray[nums[i] + bias]++;
        }
        System.out.println("计数数组为:" + Arrays.toString(counterArray) + " 最大值为:" + max + "  最小值为:" + min);
        System.out.println("===========================");

        int i = 0;/*访问原始数组时的下标计数器*/
        int j = 0;/*访问计数数组时的下标计数器*/
        /*访问计数数组,将计数数组中的元素进行转换后,重新写入到原始数组*/

        while (i < nums.length) {
            /*只要计数数组当前下标元素的值不为0,就将计数数组中的元素转换后,重新写回原始数组*/
            if (counterArray[j] != 0) {
                nums[i] = j - bias;
                counterArray[j]--;
                i++;
            } else {
                j++;
            }
            System.out.println(Arrays.toString(counterArray));
            System.out.println(Arrays.toString(nums));
            System.out.println("-----------------------");
        }
        return nums;
    }
}

桶排序(Bucket Sort)

将元素分配到不同的桶中,对每个桶中的元素进行排序,然后按顺序合并所有桶的元素。

public class BucketSort {
    /**
     * @param array
     * @param bucketCap 桶的容量,即每个桶所能放置多少个不同数值
     * @return
     */
    public static ArrayList<Integer> sortArray(ArrayList<Integer> array, int bucketCap) {
        if (array == null || array.size() < 2) return array;
        int max = array.get(0);
        int min = array.get(0);
        /*找到最大值和最小值*/
        for (int i = 0; i < array.size(); i++) {
            max = Math.max(max, array.get(i));
            min = Math.min(min, array.get(i));
        }
        /*获得桶的数量*/
        int bucketCount = (max - min) / bucketCap + 1;
        /*构建桶*/
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>();
        for (int i = 0; i < bucketCount; i++) {
            bucketArr.add(new ArrayList<>());
        }
        /*将原始数组中的数据分配到桶中*/
        for (int i = 0; i < array.size(); i++) {
            bucketArr.get((array.get(i) - min) / bucketCap).add(array.get(i));
        }
        /*看看桶中的数据分布*/
        for (int i = 0; i < bucketArr.size(); i++) {
            System.out.println("第" + i + "个桶包含数据:" + bucketArr.get(i).toString());
        }
        ArrayList<Integer> resultArr = new ArrayList<>();
        for (int i = 0; i < bucketCount; i++) {
            if (bucketCap == 1) {
                for (int j = 0; j < bucketArr.get(i).size(); j++) {
                    resultArr.add(bucketArr.get(i).get(j));
                }
            } else {
                if (bucketCount == 1) {
                    bucketCap--;
                }
                System.out.println("对第" + i + "桶中的数据再次用桶进行排序---");
                /*对桶中的数据再次用桶进行排序*/
                ArrayList<Integer> temp = sortArray(bucketArr.get(i), bucketCap);
                for (int j = 0; j < temp.size(); j++) {
                    resultArr.add(temp.get(j));
                    System.out.println("resultArr桶中的数据再次用桶进行排序---");

                }
            }
        }
        return resultArr;
    }
}

基数排序(Radix Sort)

将元素按照位数从低到高进行排序,每个位数使用稳定的排序算法。

public class RadixSort {
    public static int[] sortArray(int[] nums) {
        if (nums.length < 2) {
            return nums;
        }
        /*找出最大数*/
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            max = Math.max(max, nums[i]);
        }
        /*先算出最大数的位数,它决定了我们要进行几轮排序*/
        int maxDigit = 0;
        while (max != 0) {
            max /= 10;
            maxDigit++;
        }
        /*mod,div求模与进位,例如 12%10/1=2 个位是2, 12%100/10=1 十位是1*/
        int mod = 10, div = 1;
        /*构建桶 10进制基数0~9*/
        ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            bucketList.add(new ArrayList<Integer>());
        }
        /*按照从右往左的顺序,依次将每一位都当作一次关键字,然后按照该关键字对数组排序,每一轮排序都基于上一轮排序后的结果*/
        for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
            System.out.println("---第" + i + "轮排序开始---");
            for (int j = 0; j < nums.length; j++) {
                int num = (nums[j] % mod) / div;
                bucketList.get(num).add(nums[j]);
            }
            /*看看桶中的分布 */
            for (int j = 0; j < bucketList.size(); j++) {
                System.out.println("---第" + j + "个桶包含数据: " + bucketList.get(j));
            }
            /*桶中的数据写回原始数组,清除桶,准备下一轮排序*/
            int index = 0;
            for (int j = 0; j < bucketList.size(); j++) {
                for (int k = 0; k < bucketList.get(j).size(); k++) {
                    nums[index++] = bucketList.get(j).get(k);
                }
                bucketList.get(j).clear();
            }
            System.out.println("---第" + i + "轮排序结束---" + Arrays.toString(nums));
        }
        return nums;
    }
}