三大类六种排序总结——丑九怪

排序算法总结

插入排序

直接插入排序
  • 思路:将待排序数组分为有序部分和无序部分(对于未排序数组来说,有序部分指的就是第一个元素,无序部分是剩下的元素),每次将无序部分的第一个元素插入到有序部分中的合适位置,有序部分长度加一,对应的无序部分长度减一,一直到无序部分长度为零。
  • 图解:
    在这里插入图片描述
    如图,第一次用无序部分的第一个元素:4和前面的有序部分—[5]进行比较,并将4插入目标位置
    第二次用无序部分的第一个元素:8和前面有序部分—[4 5]进行比较,并插入到合适位置。
    重复上述过程即可完成排序
  • 代码:
public static void insertSort(int[] arr) {
        if (arr.length <= 1) {
            return;
        }
        for (int index = 1; index < arr.length; index++) { // 将所有无序部分遍历一遍
            int temp = arr[index];
            int i;
            for (i = index; i >= 1 && temp <= arr[i - 1]; i--) {  // 这个循环用来寻找要插入的位置
            }
            // 这行代码的作用是:将要插入位置之后的元素依次向后移动,为要插入的元素空出位置
            if (index - i >= 0) System.arraycopy(arr, i, arr, i + 1, index - i);
            arr[i] = temp;
        }
    }
希尔排序
  • 思路:它相当于复杂版的插入排序,他将待排序数组按照一定规则分为若干部分(每部分长度相同),对每部分中相同位置的元素使用直接插入排序,之后,再将这些部分分为更小的小块,对每个小块中相同位置的元素再次进行直接插入排序,一直分割,直至小块不可再分(也就是说,最后一次排序相当于对整个数组进行了一次直接插入排序)
  • 图解:
    在这里插入图片描述
    如图,给出了一组待排序数,将其分为两份,然后对两份中对应位置上的数据进行直接插入排序,
    图中已给出排序结果
    在这里插入图片描述
    将之前的排序结果再分为四部分,对每份中碎影位置对的元素进行直接插入排序,图中已给出本次排序结果
    在这里插入图片描述
    将上次的排序结果再分为更小的部分,对每部分中对应位置的元素使用直接插入排序,图中已给出本次排序结果

由于最后一次的结果不可再分为更小的小块,故排序结束

  • 代码:
public static void shellSort(int[] arr) {
        for (int step = arr.length / 2; step > 0; step /= 2) { // 除2就是将小块每次二等分
            for (int start = 0; start < step; start++) { // 这个循环相当于移动每个小块中的碎影位置
                innerShellSort(arr, arr.length, step, start);
            }
        }
    }

	// 这个方法就是根据给入的数据进行直接插入排序
    private static void innerShellSort(int[] arr, int len, int step, int start) {
        for (int index = start + step; index < len; index += step) {
            int temp = arr[index];
            int i;
            for (i = index; i >= step && temp <= arr[i - step]; i -= step) {
            }
            for (int j = index; j > i; j -= step) {
                arr[j] = arr[j - step];
            }
            arr[i] = temp;
        }
    }

选择排序

简单选择排序
  • 思路:依次确定数组中最大或最小的数字(降序or升序)放到数组最前面
  • 图解:
    在这里插入图片描述
    进行完第一次数据交换之后,第一个位置上的数就是最大数,如图中第一行。接着从剩下的数字中找取最大数,放在第二个位置上,如图中第二行。依次进行操作,直到数组排列完毕
  • 代码:
public static void selectSort(int[] arr) {
        int len = arr.length;
        int minIndex = 0;
        for (int index = 0; index < len; index++) {
            minIndex = index;
            for (int i = index; i < len; i++) { // 这个循环用来找到剩余数组中的最小值下标
                if (arr[minIndex] > arr[i]) {
                    minIndex = i;
                }
            }
            int temp = arr[index];
            arr[index] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
堆排序
  • 思路:这种算法将数组理解为一棵树,下标可以反映他们的树形结构。规定下标为0的元素为根节点,下标为(02+1)的元素为左节点,下标为(02+2)的元素为右节点。下标为m的元素为根节点,下标为(2 * m + 1)的元素为其左节点,下标为(2 * m + 2)的元素为其右节点,根据这个规则我们可以很容易的将一个数组理解为一个树形结构。
    此树形结构为: 堆分为大根堆(任何叶子节点必定比其父节点小)和小根堆(任何叶子节点必定比其父节点大),如果将一数组理解为一个堆,将数组的排序就可以理解为将堆转化为大根堆或者小根堆,便可以确定最大值。再依次将堆中的根节点(这里的根节点指的是总的根节点,即下标为0的元素)与堆的最后一个叶子节点交换,之后再次调整堆,使其保持为大根堆或小根堆。重复上述过程,直到所有节点完成交换,即完成排序。这个解释可能有点晦涩,看图解
  • 图解
    在这里插入图片描述
    上图是将一个数组理解为堆的结构,当然,数据结构还是数组,只是我们将其理解为堆结构
    在这里插入图片描述
    上面是堆经过调整后的结果,现在他是一个大根堆,他的每个叶子都比其对应的根小
    在这里插入图片描述
    上图是将根节点与最后一个叶子节点交换的结果,可以看到2和9交换了位置
    在这里插入图片描述
    这是将上面的堆调整过后的结果,他除了最后一个叶子节点以外,是一个大根堆
    在这里插入图片描述
    重复上面的交换过程,交换完成后,再对堆进行调整,使只成为大根堆,直到根节点及结束
  • 代码:
public static void heapSort(int[] arr) {
        // 先将arr排序为大根堆
        int count = arr.length;
        for (int index = count / 2 - 1; index >= 0; index--) {
            adjustHeap(arr, count, index);
        }
        // 再将root与最后一个交换
        for (int index = 0; index < count; count--) {
            int temp = arr[0];
            arr[0] = arr[count - 1];
            arr[count - 1] = temp;

            adjustHeap(arr, count - 1, 0);
        }
    }

    /**
     * @param arr:给入的数组
     * @param count:有效元素个数
     * @param root:根节点下标
     */
    private static void adjustHeap(int[] arr, int count, int root) {
        while (root < count / 2) {
            int leftIndex = root * 2 + 1; // 这是根节点的左节点
            int rightIndex = root * 2 + 2; // 根节点的右节点
            int maxIndex = rightIndex >= count ? leftIndex :
                    (arr[leftIndex] > arr[rightIndex] ? leftIndex : rightIndex); // 选出左右节点中的较大节点
            if (arr[maxIndex] > arr[root]) { // 如果子节点中较大的节点的值比根节点要大,也就是说,这个子节点的值是三个节点中最大的值
                int temp = arr[maxIndex];    // 那就将这个子节点和根节点交换,形成根节点最大的现象:大根堆
                arr[maxIndex] = arr[root];
                arr[root] = temp;

                root = maxIndex;
            } else {
                return;
            }
        }
    }

交换排序

冒泡排序
  • 思路:依次遍历数组,比较并交换两个相邻的数字,保持较大的数字在靠后的位置,直至数组结尾,则数组尾部为本数组中的最大数字。这个过程也可以反过来,向前进行。
  • 图解(图片来自网络):
    在这里插入图片描述
  • 代码:
public static void bubbleSort(int[] arr) {
        int count;
        for (count = arr.length; count > 0; count--) {
            for (int i = 0; i < count - 1; i++) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }
        }
    }
快速排序
  • 思路:以数组的第一个元素为分界点,将整个数组分为大于第一个元素的和小于第一个元素的两部分,再分别对分开的两部分进行同样的操作。
  • 图解(图片来自网络):
    在这里插入图片描述
  • 代码:
    public static void quickSort(int[] arr) {
        innerQuickSort(arr, 0, arr.length - 1);
    }

    private static void innerQuickSort(int[] arr, int beginIndex, int endIndex) {
        if (beginIndex >= endIndex) {
            return;
        }
        // 进行交换的动作,需要返回一个标志,标志是数据分界点
        int mid = swap(arr, beginIndex, endIndex);

        innerQuickSort(arr, beginIndex, mid - 1);
        innerQuickSort(arr, mid + 1, endIndex);
    }

    private static int swap(int[] arr, int beginIndex, int endIndex) {
        int temp = arr[beginIndex];
        
        while (beginIndex < endIndex) {
            while (beginIndex < endIndex && arr[endIndex] >= temp) {
                endIndex--;
            }
            if (beginIndex < endIndex) {
                arr[beginIndex++] = arr[endIndex];
            }
            while (beginIndex < endIndex && arr[beginIndex] <= temp) {
                beginIndex++;
            }
            if (beginIndex < endIndex) {
                arr[endIndex--] = arr[beginIndex];
            }
        }
        arr[beginIndex] = temp;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值