玩转十大经典排序算法(动图+Java代码)

本文详述了包括选择排序、插入排序、冒泡排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序和基数排序在内的十大经典排序算法,并提供了Java代码实现。文章还讨论了不同排序算法的复杂度和适用场景,并分享了在面试中应对排序问题的策略。此外,文章提及了几个基于排序的应用题,如数组的相对排序、合并区间等。
摘要由CSDN通过智能技术生成

排序算法是最基础的算法知识,也是面试笔试中必考的问题!!!!

  • 笔试题中主要是各个算法的复杂度,稳定性,所属类型和模拟几次实现结果之类的问题
    通过本文的两张总结图10张算法动态图基本都可以迎刃而解

  • 面试题中当然就是手撕代码了,自己实现一个排序方法,如果没有较好的准备,很容易就蒙圈。虽然大家在数据结构课程都学过大部分的排序算法了,但是知道原理和手写出来还是有很大区别的。

现在我就将这十种排序算法的Java代码实现也记录在这里,方便自己复习,也方便同样在准备找工作的同学

本文图片大多数都转自这里,感谢这个大佬的图,牛批!! 如果觉得我的总结的不是很清楚可以去看看大佬的思路

下面所有的代码我都经过100000次随机数据的测试了,如果有问题请私聊我及时更正。

各类排序算法的对比与分类

在这里插入图片描述
在这里插入图片描述

分类记忆

一般手撕代码都会是O(N*logN)的算法,所以一定要能熟练的手写快速排序,归并排序和堆排序

  • 初级排序(O(N*2)
    • 选择排序:每次找到最小值,然后放到待排序数组的起始位置
    • 插入排序:从前到后逐步建立有序序列,对于未排序数据,在已排序序列中从后往前扫描,找到对应位置并插入
    • 冒泡排序:嵌套循环,每次查看相邻的元素,如果逆序,则交换
  • 高级排序***(O(N*logN))
    • 快速排序:数组取标杆pivot,将元素小的放在pivot左边,大元素放右边,然后依次对左边和右边的子数组继续快速排序,达到整体有序
    • 归并排序:
      • 把长度为n的输入序列分为两个长度为n/2的子序列
      • 对两个子序列分别采用归并排序
      • 将两个排序好的子序列合并成为一个最终序列
    • 堆排序:
      • 数组元素一次建立小顶堆
      • 一次取堆顶元素,并删除
  • 特殊排序(O(N)) 针对整数
    • 计数排序(数的范围有限)
      • 统计每个数出现的次数
      • 顺序存入数组
    • 桶排序
      • 每一段数据是一个桶,桶内加入时进行排序
      • 把所有的桶有序拼接,达到整体有序
    • 基数排序
      • 从最低位开始排序
      • 排序好之后再递归调用上一位进行排序
      • 最高位有序后达到最终有序

选择排序

在这里插入图片描述

单向选择

i 记录当前有序位
j 记录遍历数组指针
minIndex 记录每次遍历的最小数的下标
每次遍历结束交换 下标为i 和下标为 minIndex 的值

/**
     * 选择排序1
     * 每次遍历查找剩余元素的最小值然后放到对应的位置
     *
     * @param arr
     */
    public static void SelectionSort1(int[] arr) {
   

        int n = arr.length;
        for (int i = 0; i < n; i++) {
   
            int minIndex = i;
            for (int j = i; j < n; j++) {
   
                if (arr[j] < arr[minIndex])
                    minIndex = j;
            }
            swap(arr, i, minIndex);
        }
    }
双向选择

left 记录左侧有序位(从小到大)
right 记录右侧有序位 (从大到小)
类似于单向选择从大到小的排序,双向选择是同时进行从小到大和从大到小的排序
每次遍历获取最大值和最小值并调整到正确位置

	/**
     * 选择排序2
     * 每次遍历查找剩余元素的最小值和最大值然后放到对应的位置
     *
     * @param arr
     */
    public static void SelectionSort2(int[] arr) {
   

        int left = 0;
        int right = arr.length - 1;

        while (left < right) {
   
            int minIndex = left;
            int maxIndex = right;


            //每次查找,保证arr[minIndex] <= arr[maxIndex]
            if (arr[minIndex] > arr[maxIndex]) {
   
                swap(arr, minIndex, maxIndex);
            }
            //从left+1到right-1遍历,找出最大最小
            for (int i = left + 1; i < right; i++) {
   
                if (arr[i] < arr[minIndex])
                    minIndex = i;
                else if (arr[i] > arr[maxIndex])
                    maxIndex = i;
            }

            swap(arr, left, minIndex);
            swap(arr, right, maxIndex);

            left++;
            right--;
        }

    }

插入排序

在这里插入图片描述

依次交换

从i位置向前依次进行比较,如果比本身大,就交换一下,直到正确位置

     /**
     * 插入排序1
     * 和前一个一次交换,直到正确位置
     *
     * @param arr
     */
    public static void InsertionSort1(int[] arr) {
   

        int n = arr.length;
        for (int i = 0; i < n; i++) {
   
            //寻找arr[i]适合的地方插入
            for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
   
                swap(arr, j, j - 1);
            }
        }
    }
依次覆盖

先暂存本身的值
从 i 位置开始向前遍历,如果arr[j-1[>arr[j] 就让arr[j-1[覆盖arr[j[的值,直到找到正确位置,将本身的值填进去

	/**
     * 插入排序2
     * 暂存插入的数据
     * 将前一个元素循环赋值给后一个元素,当发现正确位置后,将暂存数据放到对应位置
     *
     * @param arr
     */
    public static void InsertionSort2(int[] arr) {
   

        int n = arr.length;
        for (int i = 0; i < n; i++) {
   
            int e = arr[i];
            int j = i;
            for (; j > 0 && e < arr[j - 1]; j--) {
   
                arr[j] = arr[j - 1];
            }
            arr[j] = e;
        }
    }

冒泡排序

在这里插入图片描述

常规冒泡

从第一个数开始遍历,发现大于后面的数就交换,交换之后继续比较,直到有序

	/**
     * 冒泡排序1
     * 从头到尾全部遍历了
     *
     * @param arr
     */
    public static void BubbleSort1(int[] arr) {
   

        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]) {
   
                    swap(arr, j, j + 1);
                }
            }
        }
    }
优化冒泡

从第一个数开始遍历,发现大于后面的数就交换,交换之后继续比较
每次交换都记录下标记位,最后一次更新的标记位后都是有序的了,外层遍历到标记位就退出,减少了遍历次数,如果是基本有序的,最好情况可升级至O(N)

	 /**
     * 冒泡排序2
     * 如果后面m个有序,记录位置,每次遍历到有序位就跳出来
     *
     * @param arr
     */
   public static void BubbleSort2(int[] arr) {
   

        int n = arr.length;
        int new_n;
        while (n > 0) {
   
            new_n = 0;
            for (int i = 1; i < n; i++) {
   
                if (arr[i - 1] > arr[i]) {
   
                    swap(arr, i, i - 1);
                    new_n = i;//每次交换记录交换位置,最后一次交换位置之后都是有序的了
                }
            }
            n = new_n;
        }
    }

希尔排序

在这里插入图片描述

	/**
     * 希尔排序
     * @param arr
     */
    public static void ShellSort(int[] arr) {
   

        int n = arr.length;
        //增量
        int gap = 1;
        while (gap < n / 3) {
   
            gap = gap * 3 + 1;
        }
        while (gap >= 1) {
   
            for (int i = gap; i < n; i++) {
   
                //使用插入排序
                int e = arr[i];
                int j = i;
                for (; j >= gap && e < arr[j - gap]; j -= gap) {
   
                    arr[j] = arr[j - 1];
                }
                arr[j] = e;
            }
            gap /= 3;
        }
    }

归并排序

在这里插入图片描述

 /**
     * 归并排序递归方法体
     *
     * @param arr
     * @param l
     * @param mid
     * @param r   将arr[l...mid]和arr[mid+1...r]两部分进行归并
     */
    private static void merge(int[] arr, int l, int mid, int r) {
   
        int[] tmp = new int[r - l + 1];//中间数组
        int i = l;//前半段下标
        int j = mid + 1;</
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值