常用排序算法测评(冒泡、选择、插入、快排、归并、堆排)

工作中经常会有一些场景,需要对集合排序,所以对常用的几种排序算法做了一次测评,mark下

1、冒泡排序:

冒泡排序的原理比较简单,依次比较两个相邻元素,如果与期望顺序不符,则交换。如此循环,就可以将最大或最小元素按期望排到最前或最后。

    public static void bubbleSort(int[] array) {
        int n = array.length;

        for (int i=0;i<n;i++) {
            for (int j=0;j<n-i-1;j++) {
                if (array[j] > array[j+1]) {
                    int temp = array[j];
                    array[j]=array[j+1];
                    array[j+1]=temp;
                }
            }
        }
    }

2、选择排序

选择排序跟冒泡排序原理相似,选择排序是循环集合,找出最大元素,排到最后,再从未排序集合中找最大,排到未排序集合里的最后。

public static void selectSort(int[] array) {
        for (int i=0;i<array.length-1;i++) {
            int pos = i;
            int min = array[i];
            for (int j=i+1;j< array.length;j++) {
                if (array[j] < min) {
                    pos = j;
                    min = array[j];
                }
            }

            if (i != pos) {
                int temp = array[i];
                array[i] = array[pos];
                array[pos] = temp;
            }
        }
    }

3、插入排序

插入排序类似于玩扑克牌的时候,我们会把抓到的牌插入到手里已经排好顺序的牌中。插入排序就是以集合第一个元素为有序集合开始,以第二个元素作为循环开始,扫描排好序的集合,按大小插入到有序集合中。

    public static void insertSort(int[] array) {
        for (int i=0;i<array.length-1;i++) {
            for (int j=i+1;j > 0;j--) {
                if (array[j] < array[j-1]) {
                    swap(array, j, j-1);
                }
            }
        }
    }

4、快速排序

快速排序是二分排序。开始以第一个元素为基准,小于此元素的插入到之前,大于此元素的插入到之后。这样就形成了一个以初始第一个元素为中心,左右两边各是一个子集合,且左边元素都小于此元素,右边元素都大于此元素。然后再对左右两边集合做相同操作,这样集合越来越小,直到排序完成。

public static void quikSort(int[] list) {
        quik(list, 0, list.length-1);
    }

    private static void quik (int[] list, int left, int right) {
        if (left >= right)
            return;
        int middle = sort(list, left, right);

        quik(list, left, middle - 1);

        quik(list,middle + 1  , right);
    }

    private static int sort (int[] list, int start, int end) {
        int startValue = list[start];
        int position = start;

        while (start < end) {
            while (start < end && list[end] >= startValue) {
                end--;
            }
            while (start < end && list[start] <= startValue) {
                start++;
            }

            swap(list, start, end);
        }
        swap(list, start, position);

        return start;
    }

5、归并排序

归并排序是将集合一直二分,直到二分的集合是有序的,然后再跟其他集合组合,组合是遍历两个集合,按大小插入集合

private static int[] mergeSort(int[] array, int begin, int end) {
        if (begin < end) {
            int middle = (begin + end)/2;
            array = mergeSort(array, begin, middle);
            array = mergeSort(array, middle +1, end);
            merge(array, begin, middle, end);
        }
        return array;
    }

    private static void merge(int[] array, int begin, int midddle, int end) {
        int[] tempArray = new int[end - begin + 1];
        int minleft = begin;
        int maxleft = midddle + 1;
        int temppos = 0;

        while (minleft <= midddle && maxleft <= end) {
            if (array[minleft] <= array[maxleft]) {
                tempArray[temppos] = array[minleft];
                minleft++;
            } else {
                tempArray[temppos] = array[maxleft];
                maxleft++;
            }
            temppos++;
        }
        if (minleft <= midddle)
            tempArray[temppos] = array[minleft];

        if (maxleft <= end)
            tempArray[temppos] = array[maxleft];
        for (int i=0;i< tempArray.length;i++) {
            array[begin+i] = tempArray[i];
        }
    }

6、堆排序

堆排序与前边几个都不相同。堆排序是将一个集合当做二叉树来排序。这个二叉树按集合中的顺序,对应从树跟节点到叶节点。如集合:[3,2,1,4,5,6,9,7,8] 这样的一个集合,那么对应的二叉树:

开始排序,则从最后一个非根节点开始,与子节点比较,与最大子节点交换位置

 最终排序如下:

 这就是大根树,即父节点大于两个子节点,此时对应集合为:[9, 8, 6, 7, 5, 3, 1, 2, 4]

集合中的最大值在根节点处。

这时把根节点的移动到最末,集合则为:[4, 8, 6, 7, 5, 3, 1, 2, 9],然后对集合长度-1的集合重复上面操作。最终到集合完全排序。

public static void heapSort(int[] array) {
        //构造大根堆
        for (int i = array.length/2-1 ; i >= 0; i--) {
            buildMaxHeap(array, i, array.length);
        }

        System.out.println("maxHeap=" + Arrays.toString(array));
        for (int i = array.length-1; i > 0; i--) {
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            buildMaxHeap(array, 0, i);
        }
        System.out.println("2maxHeap=" + Arrays.toString(array));
    }

    /*
     * 构造大根堆
     * 从最后一个非叶子节点开始
     * 需处理的集合范围,end值
     */

    private static void buildMaxHeap (int[] array, int i, int length) {
        int temp = array[i];
        //步长为j*2+1,即指向节点的左子节点
        for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
            if (j + 1 < length && array[j] < array[j+1]) {
                j++; // 左子节点小于右子节点,则直接去比较右子节点与根节点大小
            }
            if (array[j] > temp) {
                array[i] = array[j];
//                array[j] = temp; // temp 还是要与子节点做比较的,所以不用换
                i = j;
            } else
                break;
        }
        array[i] = temp;
    }

代码完毕,开始测试

在数据量较小时,1000以下,几种算法耗时相差不大

当数量级大于10000时,快排,归并,堆排依然很稳,耗时很小,但冒泡、选择、插入性能下降

数据量到100000时,冒泡、选择、插入直接弃用。快排,插入,堆排依然很强。

测评结果就不贴了,动动手感受更深刻。

其他像计数排序,基数排序,桶排序这些适用于特定集合的算法,对于元素值在有限区间内的集合,性能还是不错的,但对于元素值比较杂乱的就不太适用了。可以了解借鉴下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值