• 常用的排序算法介绍和在JAVA的实现(一)


    一、写随笔的原因:排序比较常用,借此文介绍下排序常用的算法及实现,借此来MARK一下,方便以后的复习。(本人总是忘得比较快)

    二、具体的内容:

    1.插入排序

    插入排序:在前面已经排好序的序列中找到合适的插入位置。

    插入排序又可细分为:直接插入排序,二分法插入排序,希尔排序

    (1)直接插入排序:简单来说,就是在每一步将一个待排序的数据,从后向前找到合适的位置插入,知道全部数据插入完,排序结束。(从第二个数开始,第一个数插入时没有其他数据,所以直接不用管)

    Java代码实现如下:

        /*
        直接插入排序
        */
        public static int[] directInsertSort(int[] a) {
            // 实现从小到大排序
            for (int i = 1; i < a.length; i++) {
                int temp = a[i]; // 存入当前待排序的数据
                int j;
                for (j = i - 1; j >= 0; j--) { // 从后向前依次比较,插入到合适的位置
                    // (a[j]大于temp往后移动一位)
                    if (temp < a[j]) {
                        a[j + 1] = a[j];
                    } else {
                        break;  // a[j]不大于temp,则找到了合适的位置,直接退出循环
                    }
                }
                a[j + 1] = temp; // 把当前待排序的数据放入到找的位置(因为是从大到小所以放到j的后面)
            }
            return a;
        }

    (2)二分法插入排序:思想都是插入排序的思想,只是在查找合适位置时是通过二分法来找位置的。

    下面有个图可以很好的解释(盗图的):

    Java代码实现如下:

        /*
        二分法插入排序
         */
        public static void binaryInsertSort(int[] a) {
            for (int i = 0; i < a.length; i++) {
                int temp = a[i];  // 存入当前待排序的数据
                int low = 0;  //low的下标
                int high = i - 1; //high的下标
                int mid = 0;  //mid下标
                while (low <= high) {
                    mid = (low + high) / 2;  //算出mid位置
                    if (temp < a[mid]) {   // temp小于mid位置的值,则继续与左边部分的位置使用二分
                        high = mid - 1;  // 这时候的右下标需要修改为mid前一位
                    } else {       // temp不小于mid位置的值,则继续与右边边部分的位置使用二分
                        low = mid + 1;   // 这时候的右下标需要修改为mid后一位
                    }
                }
                // 找到位置后需要将原先位置上及后面的的数据向后平移一位,腾出位置插入
                for (int j = i - 1; j >= low; j--) {
                    a[j + 1] = a[j];
                }
                if (low != i) {  //low == i,则不需要变化,本来的位置就是正确的
                    a[low] = temp;
                }
            }
        }

    (3)希尔排序:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2,直重复上述分组和排序操作;至di=1,即所有记录放进一个组中排序为止。

    Java代码实现如下:

        public static void shellSort(int[] a) {
            int d = a.length;
            // 不断缩小d,直至d=1
            while (true) {
                d = d/2;
                for (int x = 0; x < d; x++) {
                    for (int i = x + d; i < a.length; i = i + d) {
                        int temp = a[i];
                        int j;
                        // 相当于把直接插入排序的1变成了d
                        for (j = i - d; j >= 0 && a[j] > temp; j = j - d) {
                            a[j + d] = a[j];
                        }
                        a[j + d] = temp;
                    }
                }
                if (d == 1) {
                    break;
                }
            }
        }

    2.选择排序

    选择排序:在剩余的待排序记录序列中找到最小数据。

    选择排序又可细分为:直接选择排序,堆排序。

    (1)直接选择排序:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

    如下图:

    Java代码实现如下:

        /*
        直接选择排序
        */
        public static void directSelectSort(int[] a) {
            for (int i = 0; i < a.length; i++) {
                int min = a[i];
                int n = i; // 最小数的索引
                for (int j = i + 1; j < a.length; j++) {
                    if (a[j] < min) { // 找出最小的
                        min = a[j];
                        n = j;
                    }
                }
                // 最小的一个数与i位置的数交换
                a[n] = a[i]; // n为最小的一个数的索引
                a[i] = min;
            }
        }

    (2)堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。

      首先简单了解下堆结构:堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

    同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子

     我们用简单的公式来描述一下堆的定义就是:

    大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

    小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

    堆排序的基本思想是:

    1.将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。

    2.将其与末尾元素进行交换,此时末尾就为最大值。

    3.然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。

    代码实现如下:

        /*
        堆排序
        */
        public static void heapSort(int[] a) {
            int arrayLength = a.length;
            // 循环建堆
            for (int i = 0; i < arrayLength - 1; i++) {
                // 建堆
                buildMaxHeap(a, arrayLength - 1 - i);
                // 交换堆顶和最后一个元素
                swap(a, 0, arrayLength - 1 - i);
            }
        }
    
        // 对data数组从0到lastIndex建大顶堆
        public static 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;
                    }
                }
            }
        }
    
        // 交换
        private static void swap(int[] data, int i, int j) {
            int tmp = data[i];
            data[i] = data[j];
            data[j] = tmp;
        }

    三、总结:

      本文主要是对插入排序和选择排序进行了讲解,并通过代码来实现。还有一些像交换排序,归并排序,基数排序等就作为第二部分内容在下次在写吧。

  • 相关阅读:
    c语言变量的交换
    牛客网 多多的电子字典
    算法笔记----背包九讲 ③多重背包问题
    统计学习方法 课后习题第五章
    2020.8.2 19:00-21:00 拼多多算法岗笔试
    python构建模块
    leetcode 剑指 Offer 51. 数组中的逆序对
    pytorch的内部计算
    matplotlib
    矩阵微积分
  • 原文地址:https://www.cnblogs.com/black-fact/p/10965048.html
Copyright © 2020-2023  润新知