五大排序算法——冒泡,插入,选择,希尔,快排的解析和java代码实现

1、冒泡排序

1.从头到尾遍历所有元素,如果当前元素大于下一个元素,则进行交换。以此类推,则最大的元素将会被放到数组的末尾。

2.数组总长度减少1,继续重复上一步操作,直到最外层循环的元素个数变成1则排序完成。

    public static void bubbleSort(int[] arr) {
        //1、所有元素的数量
        for (int i = arr.length - 1; i > 0; i--) {
            //2、交换元素的过程
            for (int j = 0; j < i; j++) {
                //3、设置交换元素的条件
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

冒泡排序算法只需要常数数量的额外的空间,所以空间复杂度为O(1);

当数组是顺序序列时,时间复杂度为O(N);

当数组是倒序序列时,时间复杂度为O(N^2);//通常认为的平均复杂度也是如此

冒泡排序是一种稳定的排序算法;

2、选择排序

1、假设第一个元素是最小的元素,不断和后面的元素进行比较,直到找出最小的元素的下标,赋值给minIndex;

2、如果minIndex和第一个元素的下标(i)不相同,那么就进行数据交换;

3、重复上述步骤

    public static void selectionSort(int[] arr) {
        //1、遍历所有元素
        for (int i = 0; i < arr.length; i++) {
            //2、假设第一个元素就是数值最小的元素
            int minIndex = i;

            //3、使用当前的元素和其它所有元素做对比
            for (int j = i; j < arr.length; j++) {
                //4、元素进行比较
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;//如果发现arr[j]比arr[minIndex]要小,则下标赋值给最小索引,即把j赋值给minIndex
                }
            }
            //4、最后进行真正的数据交换,而前面的步骤只是下标赋值
            if (minIndex != i) {//注意,一开始的minIndex是和i相等的,所以需要判断minIndex和i不相等的情况。
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }

时间复杂度和空间复杂度和冒泡排序是相同的,但是数据交换的操作更少,性能会高于冒泡排序;

需要注意的是,选择排序在标准语法上,相同的元素也是需要交换的,因此是一种不稳定的排序算法;

如何解决它的不稳定性呢?个人认为是开辟一个新的数组,将元素放入新的数组而不是进行交换,这种做法显然会牺牲空间。

3、插入排序

1、插入第一个元素,并指定该元素为已排序部分。

2、然后插入第二个元素,在和第一个元素构成的区域进行排序。

3、重复上述步骤

    public static void insertionSort(int[] arr) {
        //1、循环插入元素
        for (int i = 0; i < arr.length; i++) {//如果这一步是从左往右的,那么下一步数据比较就应该从右往左为佳
                                              //如果同向比较,可能会造成位置错乱的问题
            //2、遍历已经存在于数组的元素,并进行排序(类似冒泡)
            for (int j = i - 1; j >= 0; j--) {//应该从右往左进行数据比较
                //3、对元素数值进行交换操作
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

时间复杂度和空间复杂度与上述两种排序算法都相同。

在有序部分元素和待插入元素相等的时候,待插入的元素将被放在前面,因而插入排序是稳定的。

4、希尔排序

1、将所有数据分成(array.length/2)组

2、循环遍历每个小组,并对其进行排序

3、把步长变为原先的二倍,重复上述操作

    public static void shellSort(int[] arr) {
        //1、记录一共有多少个组
        int gap = arr.length / 2;

        //声明一个变量,记录当前值
        int current;

        //2、循环遍历小组
        while (gap > 0) {
            //对小组中的数据进行插入排序
            for (int j = gap; j < arr.length; j++) {
                current = arr[j];//得到需要比较的数据
                int preIndex = j - gap;//得到小组内上一个数据的下标
                //进行插入排序
                while (preIndex >= 0 && current < arr[preIndex]) {
                    //数据交换
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                arr[preIndex + gap] = current;

            }
            gap = gap / 2;
        }
    }

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。

                                                                                                                                                                              ——摘自百度百科

空间复杂度认为是O(1)或者O(N)

时间复杂度通常认为是O(N^1.3~N^2);

5、快速排序

1、记录一个基准数字,选取未排序数组的第一个元素作为基准数字;

2、数组第一个元素的下标记作i,数组最后一个元素的下标记作j;

3、从左边开始找到比基准数字小的元素,从右边开始找到比基准数字大的元素,然后将这两个元素交换;

4、将基准数字进行调整,把基准数字和下标为i的元素进行交换,并且基准数字接下来不再参与排序;

5、递归执行上述操作

    public static void quickSort(int[] arr, int left, int right) {
        //设置递归推出条件
        if (left > right) {
            return;
        }
        //记录左边编号和右边编号
        int i = left;
        int j = right;
        //记录基准数字
        int base = arr[left];

        //主要操作
        while (i != j) {
            //右侧编号查找数字
            while (j > i && arr[j] >= base) {
                j--;
            }
            //左侧编号查找数字
            while (i < j && arr[i] <= base) {
                i++;
            }
            //数字交换
            if (i < j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        //基准数字调整,即基准数字和i下标位置数字交换
        arr[left] = arr[i];
        arr[i] = base;

        //i位置是基准数字,不再参与排序过程
        //左侧数字进行二次分类
        quickSort(arr, left, i - 1);

        //右侧数字进行二次分类
        quickSort(arr, i + 1, right);
    }

快速排序是上面五种排序算法中效率较高的一种,空间复杂度为O(log N)

时间复杂度为O(N * log N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值