你不得不知的八大排序算法(Java实现)

版权声明:fangwh https://blog.csdn.net/qq_40804005/article/details/82148164

本文主要讲述八种常见的排序算法,使用Java代码实现
1、冒泡排序
2、选择排序
3、插入排序
4、希尔排序
5、快速排序
6、归并排序
7、堆 排 序
8、桶 排 序
各个排序比较

1-冒泡排序

1、第一次从0-(lenght-1)两两比较数据,大的沉底到(lenght-1);
2、第二次从0-(lenght-2)两两比较数据,大的沉底(lenght-2);
…….

public class BubbleSort {

    public void sort(int[] arr) {
        int temp = 0;
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) 
                {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            System.out.println("第"+(i+1)+"趟:");
            System.out.println(Arrays.toString(arr));
        }
    }
    @Test
    public void test() {
        int[] arr={32,69,58,24,12,36,18,54};
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
    }
}
结果:

初始数组:
[32, 69, 58, 24, 12, 36, 18, 54]
第1趟:
[32, 58, 24, 12, 36, 18, 54, 69]
第2趟:
[32, 24, 12, 36, 18, 54, 58, 69]
第3趟:
[24, 12, 32, 18, 36, 54, 58, 69]
第4趟:
[12, 24, 18, 32, 36, 54, 58, 69]
第5趟:
[12, 18, 24, 32, 36, 54, 58, 69]
第6趟:
[12, 18, 24, 32, 36, 54, 58, 69]
第7趟:
[12, 18, 24, 32, 36, 54, 58, 69]

改进

不难发现上面的结果从第五趟开始数组已经排好序了,后面的几趟都相当于白操作了;对于冒泡排序,其实我们可以设置一个标志,通过标志判断它是否发生了数据交换,在这一趟里如果未发生数据交换,数组其实就已经排好序了,这时我们break退出循环即可。

public class BubbleSort {

    public void sort(int[] arr) {
        int temp = 0;
        int n = arr.length;
        boolean flag=true;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) 
                {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag=false;
                }
            }
            if(flag){
                break;
            }
            flag=true;
            System.out.println("第"+(i+1)+"趟:");
            System.out.println(Arrays.toString(arr));
        }
    }
    @Test
    public void test() {
        int[] arr1={32,69,58,24,12,36,18,54};
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr1);
    }
}
结果:

初始数组:
[12, 18, 24, 32, 36, 54, 58, 69]
第1趟:
[32, 58, 24, 12, 36, 18, 54, 69]
第2趟:
[32, 24, 12, 36, 18, 54, 58, 69]
第3趟:
[24, 12, 32, 18, 36, 54, 58, 69]
第4趟:
[12, 24, 18, 32, 36, 54, 58, 69]
第5趟:
[12, 18, 24, 32, 36, 54, 58, 69]

2-选择排序

1、第0位设置为标志位,从后遍历(length-1~1)数组选出最小值,与标志位数据交换;
2、第1位设置为标志位,从后遍历(length-1~2)数组选出最小值,与标志位数据交换;
……

public class SelectSort {
    public void sort(int[] arr) {
        int n = arr.length; // 数组长度
        int temp = 0; // 中间变量

        for (int i = 0; i < n-1; i++) {
            int k = i;// 待确定的位置
            // 选择出应该在第i个位置的数
            for (int j = n - 1; j > i; j--) {
                if (arr[j] < arr[k]) {
                    k = j;
                }
            }
            // 交换两个数
            temp = arr[i];
            arr[i] = arr[k];
            arr[k] = temp;

            System.out.println("第"+(i+1)+"趟:");
            System.out.println(Arrays.toString(arr));
        }
    }
    @Test
    public void test(){
        int[] arr = { 32, 69, 58, 24, 12, 36, 18, 54 };
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
    }
}
结果:

初始数组:
[32, 69, 58, 24, 12, 36, 18, 54]
第1趟:
[12, 69, 58, 24, 32, 36, 18, 54]
第2趟:
[12, 18, 58, 24, 32, 36, 69, 54]
第3趟:
[12, 18, 24, 58, 32, 36, 69, 54]
第4趟:
[12, 18, 24, 32, 58, 36, 69, 54]
第5趟:
[12, 18, 24, 32, 36, 58, 69, 54]
第6趟:
[12, 18, 24, 32, 36, 54, 69, 58]
第7趟:
[12, 18, 24, 32, 36, 54, 58, 69]

3-插入排序

从前向后遍历数组,用temp记录当前值,假如temp比前面的值小,则将前面的值后移。

public class InsertSort {
    public void sort(int[] arr) {
        int n = arr.length;
        int temp = 0;
        int j = 0;
        for (int i = 0; i < n; i++) {
            temp = arr[i];
            // 假如temp比前面的值小,则将前面的值后移
            for (j = i; j > 0 && temp < arr[j - 1]; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = temp;
            System.out.println("第"+(i+1)+"趟:");
            System.out.println(Arrays.toString(arr));
        }
    }
    @Test
    public void test(){
        int[] arr={32,69,58,24,12,36,18,54};
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
    }
}
结果:

初始数组:
[32, 69, 58, 24, 12, 36, 18, 54]
第1趟:
[32, 69, 58, 24, 12, 36, 18, 54]
第2趟:
[32, 69, 58, 24, 12, 36, 18, 54]
第3趟:
[32, 58, 69, 24, 12, 36, 18, 54]
第4趟:
[24, 32, 58, 69, 12, 36, 18, 54]
第5趟:
[12, 24, 32, 58, 69, 36, 18, 54]
第6趟:
[12, 24, 32, 36, 58, 69, 18, 54]
第7趟:
[12, 18, 24, 32, 36, 58, 69, 54]
第8趟:
[12, 18, 24, 32, 36, 54, 58, 69]

4-希尔排序

设置每次比较的间隔,间隔相同的数据,两两比较;
间隔–;
直至间隔为1,排序完成;

public class ShellSort {
    public void sort(int[] arr) {
        int j = 0;
        int temp = 0;
        // 每次将步长缩短为原来的一半
        for (int step = arr.length / 2; step > 0; step /= 2) {
            for (int i = step; i < arr.length; i++) {
                temp = arr[i];
                for (j = i; j >= step; j -= step) {
                    if (temp < arr[j - step])// 如想从小到大排只需修改这里
                    {
                        arr[j] = arr[j - step];
                    } else {
                        break;
                    }
                }
                arr[j] = temp;
            }
            System.out.println("STEP:"+step);
            System.out.println(Arrays.toString(arr));
        }
    }

    @Test
    public void test(){
        int[] arr={32,69,58,24,12,36,18,54};
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
    }
}
结果:

初始数组:
[32, 69, 58, 24, 12, 36, 18, 54]
STEP:4
[12, 36, 18, 24, 32, 69, 58, 54]
STEP:2
[12, 24, 18, 36, 32, 54, 58, 69]
STEP:1
[12, 18, 24, 32, 36, 54, 58, 69]

5-快速排序

选择一个中轴,比它小的放到左边,比它大的放到右边;
然后左边右边继续递归调用,直至排序完成;

public class QuickSort {
    public int count =1;
    public int getMiddle(int[] numbers, int low, int high) {
        int temp = numbers[low]; // 数组的第一个作为中轴
        while (low < high) {
            while (low < high && numbers[high] > temp) {
                high--;
            }
            numbers[low] = numbers[high];// 比中轴小的记录移到低端
            while (low < high && numbers[low] < temp) {
                low++;
            }
            numbers[high] = numbers[low]; // 比中轴大的记录移到高端
        }
        numbers[low] = temp; // 中轴记录到尾
        return low; // 返回中轴的位置
    }

    public void sort(int[] numbers,int low,int high)
    {
        if(low < high)
        {
            int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
            System.out.println("第"+(count++)+"趟:");
            System.out.println(Arrays.toString(numbers));
            sort(numbers, low, middle-1);   //对低字段表进行递归排序
            sort(numbers, middle+1, high); //对高字段表进行递归排序
        }

    }
    @Test
    public void test() {
        int[] arr = { 32, 69, 58, 24, 12, 36, 18, 54 };
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr, 0, arr.length - 1);
    }
}
结果:

初始数组:
[32, 69, 58, 24, 12, 36, 18, 54]
第1趟:
[18, 12, 24, 32, 58, 36, 69, 54]
第2趟:
[12, 18, 24, 32, 58, 36, 69, 54]
第3趟:
[12, 18, 24, 32, 54, 36, 58, 69]
第4趟:
[12, 18, 24, 32, 36, 54, 58, 69]

6-归并排序

递归将数据划分为左右两边,直至长度为1;
然后将数据合并,全部合并完成即数组排好了序。

public class MergeSort {
    public void sort(int[] arr, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            sort(arr, low, mid);
            // 右边
            sort(arr, mid + 1, high);
            // 左右归并
            merge(arr, low, mid, high);
            System.out.println("归并:");
            System.out.println(Arrays.toString(arr));
        }
    }

    public static void merge(int[] arr, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low; // 左指针
        int j = mid + 1;// 右指针
        int k = 0;
        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }
        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = arr[i++];
        }
        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = arr[j++];
        }
        // 把新数组中的数覆盖arr数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            arr[k2 + low] = temp[k2];
        }
    }

    @Test
    public void test() {
        int[] arr = { 69, 32, 58, 24, 39, 36, 54, 18 };
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr, 0, arr.length - 1);
    }
}
结果:

初始数组:
[69, 32, 58, 24, 39, 36, 54, 18]
归并:
[32, 69, 58, 24, 39, 36, 54, 18]
归并:
[32, 69, 24, 58, 39, 36, 54, 18]
归并:
[24, 32, 58, 69, 39, 36, 54, 18]
归并:
[24, 32, 58, 69, 36, 39, 54, 18]
归并:
[24, 32, 58, 69, 36, 39, 18, 54]
归并:
[24, 32, 58, 69, 18, 36, 39, 54]
归并:
[18, 24, 32, 36, 39, 54, 58, 69]

7-堆排序

构建最大堆

public class HeapSort {

    public void sort(int[] arr){
        int n = arr.length;
        // 循环建堆
        for (int i = 0; i < n - 1; i++) {
            // 建堆
            buildMaxHeap(arr, n - 1 - i);
            // 交换堆顶和最后一个元素
            swap(arr, 0, n - 1 - i);
            System.out.println("第"+(i+1)+"趟:");
            System.out.println(Arrays.toString(arr));
        }
    }

    // 对data数组从0到lastIndex建大顶堆
    public void buildMaxHeap(int[] data, int lastIndex) {
        // 从lastIndex处节点(最后一个节点)的父节点开始
        for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
            // k保存正在判断的节点
            int k = i;
            // 如果当前k节点的子节点存在
            while (k * 2 + 1 <= lastIndex) {
                // k节点的左子节点的索引
                int biggerIndex = 2 * k + 1;
                // 如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
                if (biggerIndex < lastIndex) {
                    // 若果右子节点的值较大
                    if (data[biggerIndex] < data[biggerIndex + 1]) {
                        // biggerIndex总是记录较大子节点的索引
                        biggerIndex++;
                    }
                }
                // 如果k节点的值小于其较大的子节点的值
                if (data[k] < data[biggerIndex]) {
                    // 交换他们
                    swap(data, k, biggerIndex);
                    // 将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
                    k = biggerIndex;
                } else {
                    break;
                }
            }
        }
    }
    // 交换
    public void swap(int[] data, int i, int j) {
        int tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    }

    @Test
    public void test() {
        int[] arr = { 32, 69, 58, 24, 39, 36, 54, 18 };
        System.out.println("初始化数据:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
    }
}
结果:

初始化数据:
[32, 69, 58, 24, 39, 36, 54, 18]
第1趟:
[18, 39, 58, 24, 32, 36, 54, 69]
第2趟:
[18, 39, 54, 24, 32, 36, 58, 69]
第3趟:
[18, 39, 36, 24, 32, 54, 58, 69]
第4趟:
[18, 32, 36, 24, 39, 54, 58, 69]
第5趟:
[24, 32, 18, 36, 39, 54, 58, 69]
第6趟:
[18, 24, 32, 36, 39, 54, 58, 69]
第7趟:
[18, 24, 32, 36, 39, 54, 58, 69]

8-桶排序

消耗内存大,一般不建议使用。

public class BucketSort {
    public void sort(int[] arr){
        int n = arr.length;
        List<ArrayList<Integer>> Blist = new ArrayList<>(n);
        for(int i = 0; i < n; i++){
            Blist.add(new ArrayList<Integer>());
        }
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for(int a : arr){
            max = Math.max(max, a);
            min = Math.min(min, a);
        }
        for(int i : arr){
            int index = (int)((i-min) / (max-min+1.0) * arr.length); 
            Blist.get(index).add(i);
        }

        for(int i = 0; i < Blist.size(); i++){
            Collections.sort(Blist.get(i));
        }
        System.out.println(Blist);
        int j = 0;
        for(ArrayList<Integer> list : Blist){
            for(int i : list){
                arr[j++] = i;
            }
        }
    }
    @Test
    public void test(){
        int arr[] = {1,6,6,8,3,5,9,2,1,5};
        System.out.println("初始数组:");
        System.out.println(Arrays.toString(arr));
        sort(arr);
        System.out.println("桶排序:");
        System.out.println(Arrays.toString(arr));
    }
}
结果:

初始数组:
[1, 6, 6, 8, 3, 5, 9, 2, 1, 5]
[[1, 1], [2], [3], [], [5, 5], [6, 6], [], [8], [9], []]
桶排序:
[1, 1, 2, 3, 5, 5, 6, 6, 8, 9]

各个排序比较

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_40804005/article/details/82148164