当前位置: 首页 > news >正文

排序算法总结

在这里插入图片描述

1.插入排序(扑克排序)

public static void insertionSort(int[] array) {
      // 外层循环:遍历未排序部分(从第二个元素开始)
      for (int i = 1; i < array.length; i++) {
          int current = array[i]; // 当前待插入元素
          int j = i - 1;          // 已排序部分的最后一个索引

          // 内层循环:从后向前扫描已排序部分
          // 若当前元素更小,则将元素向右移动
          while (j >= 0 && array[j] > current) {
              array[j + 1] = array[j]; // 元素右移
              j--;
          }

          // 将当前元素插入正确位置
          array[j + 1] = current;
      }
  }

2. 希尔排序

public static void shellSort(int[] array) {
        if (array == null || array.length <= 1) return;

        // 初始化增量为数组长度的一半[3,4](@ref)
        int gap = array.length / 2;
        
        while (gap > 0) {
            // 对每个增量间隔的子序列进行插入排序[2,5](@ref)
            for (int i = gap; i < array.length; i++) {
                int temp = array[i];  // 当前待插入元素
                int j = i - gap;     // 前一个元素的索引
                
                // 插入排序逻辑:比当前元素大的都向后移动
                while (j >= 0 && array[j] > temp) {
                    array[j + gap] = array[j];
                    j -= gap;
                }
                array[j + gap] = temp; // 插入到正确位置
            }
            gap /= 2; // 缩小增量[3,6](@ref)
        }
    }

3. 直接选择

public static void selectionSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            // 寻找[i, n)区间内的最小值索引
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 仅当找到更小值时交换(减少不必要的交换)
            if (minIndex != i) {
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }

4. 堆排序

 /**
     * 堆排序入口方法
     * @param arr 待排序数组
     */
    public static void heapSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;
        
        // 1. 构建最大堆(时间复杂度O(n))[1,6](@ref)
        int n = arr.length;
        for (int i = n/2 - 1; i >= 0; i--) {  // 从最后一个非叶子节点开始
            heapify(arr, n, i);
        }
        
        // 2. 逐个提取堆顶元素(时间复杂度O(n logn))[3,8](@ref)
        for (int i = n-1; i > 0; i--) {
            // 交换堆顶与当前末尾元素
            swap(arr, 0, i);
            // 调整剩余元素维持堆性质
            heapify(arr, i, 0);
        }
    }
    
    /**
     * 堆化操作(向下调整)
     * @param arr 待调整数组
     * @param n   堆的有效长度
     * @param i   当前调整的节点索引
     */
    private static void heapify(int[] arr, int n, int i) {
        int largest = i;        // 初始化最大值为当前节点
        int left = 2*i + 1;     // 左子节点索引
        int right = 2*i + 2;    // 右子节点索引
        
        // 找出当前节点与子节点的最大值[1,6](@ref)
        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }
        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }
        
        // 若最大值不是当前节点,需要交换并递归调整[8](@ref)
        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, n, largest);  // 递归调整受影响的子树
        }
    }
    
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    

5. 冒泡排序

/**
     * 冒泡排序优化版(带提前终止机制)
     * @param arr 待排序数组
     */
    public static void bubbleSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;
        
        int n = arr.length;
        // 外层循环控制排序轮次
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false;  // 优化点:标记是否发生交换[4](@ref)
            // 内层循环执行相邻元素比较(每轮减少i个已排序元素)
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换相邻元素
                    swap(arr, j, j + 1);
                    swapped = true;
                }
            }
            // 若本轮未交换则提前终止[4](@ref)
            if (!swapped) break;
        }
    }

    /**
     * 元素交换方法
     * @param arr 数组
     * @param i 索引1
     * @param j 索引2
     */
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

6. 快速排序

/**
     * 快速排序核心方法(双指针优化版)
     * @param arr 待排序数组
     * @param low 左边界索引
     * @param high 右边界索引
     */
    public static void quickSort(int[] arr, int low, int high) {
        if (low >= high) return;  // 递归终止条件[2,5](@ref)
        
        int pivot = partition(arr, low, high);  // 执行分区操作
        quickSort(arr, low, pivot - 1);         // 递归处理左子数组
        quickSort(arr, pivot + 1, high);        // 递归处理右子数组
    }

    /**
     * 分区操作(原地交换版本)
     * @return 基准值的最终位置
     */
    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[low];  // 基准值选择优化(此处简化为取首元素)[2](@ref)
        int left = low, right = high;
        
        while (left < right) {
            // 从右向左找第一个小于基准的元素[5](@ref)
            while (left < right && arr[right] >= pivot) right--;
            // 从左向右找第一个大于基准的元素[5](@ref)
            while (left < right && arr[left] <= pivot) left++;
            if (left < right) swap(arr, left, right);  // 交换不符合条件的元素
        }
        swap(arr, low, left);  // 将基准值放到正确位置[5](@ref)
        return left;
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

7. 归并排序

 /**
     * 归并排序入口方法
     * @param arr 待排序数组
     */
    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;
        int[] temp = new int[arr.length];  // 创建临时数组避免递归中频繁开辟空间[6,7](@ref)
        sort(arr, 0, arr.length - 1, temp);
    }

    /**
     * 递归分治与合并
     * @param arr   原数组
     * @param left  左边界索引
     * @param right 右边界索引
     * @param temp  临时数组
     */
    private static void sort(int[] arr, int left, int right, int[] temp) {
        if (left < right) {
            int mid = left + (right - left) / 2;  // 防溢出写法[6](@ref)
            
            // 分治递归(类似二叉树后序遍历)
            sort(arr, left, mid, temp);       // 处理左半区间[4,7](@ref)
            sort(arr, mid + 1, right, temp);  // 处理右半区间[4,7](@ref)
            
            // 合并已排序的子数组
            merge(arr, left, mid, right, temp);  // 核心合并逻辑[6,10](@ref)
        }
    }

    /**
     * 合并两个有序子数组
     * @param left  左子数组起始索引
     * @param mid   中间分隔索引
     * @param right 右子数组结束索引
     */
    private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        int i = left;      // 左子数组指针
        int j = mid + 1;   // 右子数组指针
        int t = 0;         // 临时数组指针

        // 比较填充临时数组
        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) {  // 保持稳定性(相等时左子数组优先)[10](@ref)
                temp[t++] = arr[i++];
            } else {
                temp[t++] = arr[j++];
            }
        }

        // 处理剩余元素
        while (i <= mid) temp[t++] = arr[i++];    // 左子数组剩余元素[7](@ref)
        while (j <= right) temp[t++] = arr[j++];  // 右子数组剩余元素[7](@ref)

        // 将临时数组数据拷贝回原数组
        t = 0;
        while (left <= right) {
            arr[left++] = temp[t++];  // 原地更新原数组[6,8](@ref)
        }
    }

8. 基数排序

    /**
     * 基数排序核心方法(LSD优化版)
     * @param arr 待排序数组(仅支持非负整数)
     */
    public static void radixSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;

        // 1. 获取最大值确定最大位数[4,6](@ref)
        int max = Arrays.stream(arr).max().getAsInt();
        int exp = 1; // 当前排序位数(1表示个位)

        // 2. 从低位到高位循环处理每个数字位[1,6](@ref)
        while (max / exp > 0) {
            countingSortByDigit(arr, exp);
            exp *= 10; // 升到更高位:个位→十位→百位...
        }
    }

    /**
     * 按指定位数进行计数排序(稳定版)
     * @param exp 当前处理位数的权值(例如个位=1,十位=10)
     */
    private static void countingSortByDigit(int[] arr, int exp) {
        int n = arr.length;
        int[] output = new int[n];   // 临时输出数组
        int[] count = new int[10];  // 0-9的计数器[6](@ref)

        // 统计当前位各数字出现次数[5](@ref)
        for (int num : arr) {
            int digit = (num / exp) % 10;
            count[digit]++;
        }

        // 计算前缀和确定元素最终位置[5,6](@ref)
        for (int i = 1; i < 10; i++) {
            count[i] += count[i-1];
        }

        // 逆序填充保证稳定性[5,6](@ref)
        for (int i = n-1; i >= 0; i--) {
            int digit = (arr[i] / exp) % 10;
            output[--count[digit]] = arr[i];
        }

        // 将排序结果写回原数组[6](@ref)
        System.arraycopy(output, 0, arr, 0, n);
        Arrays.fill(count, 0); // 重置计数器
    }

相关文章:

  • Spring的IOC
  • 回溯算法经典题目
  • 2025年03月18日柯莱特(外包宁德)一面前端面试
  • spring boot 拦截器
  • Spring Boot 集成 Elasticsearch怎样在不启动es的情况下正常启动服务
  • 什么是API❓
  • 语法: erase_program_eeprom(address)
  • NR SRS Configuration
  • C语言基础系列【27】typedef
  • AF3 quat_to_rot函数解读
  • 线性筛和欧拉函数
  • mysql实例2
  • AF3 rot_to_quat函数解读
  • 群体智能优化算法-蚁狮优化算法(Ant Lion Optimizer, ALO,含Matlab源代码)
  • 【愚公系列】《高效使用DeepSeek》024-儿童教育
  • 2025:sql注入详细介绍
  • 并发和并行、同步和异步、进程和线程的关系
  • 【MySQL篇】索引特性
  • pcap流量包分析
  • Linux 内核源码阅读——ipv4
  • 商务部再回应中美经贸高层会谈:美方要拿出诚意、拿出行动
  • 98岁动物学家、北京大学教授杨安峰逝世
  • 少年中国之少年的形塑
  • 四问当前旱情:还会持续多久
  • 两国战机均未侵入对方领空,巴方公布对印回击细节
  • 央视315晚会曝光“保水虾仁”后,湛江4家涉事企业被罚超800万元