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

数据结构==排序==

一、插入排序类

1. 直接插入排序

算法介绍:直接插入排序是最简单的插入排序算法,核心思想是将待排序元素逐个插入到已排序序列的合适位置。默认第一个元素为有序序列,后续元素依次与有序序列从后往前比较,找到位置后插入,使序列始终保持有序。

public class Sort1 {/*** 直接插入排序* 步骤:* 1. 从第一个元素开始,默认其为已排序序列* 2. 依次取后续元素作为待插入元素,保存其值* 3. 与已排序序列从后往前比较,若已排序元素大于待插入元素则后移* 4. 找到插入位置后,将待插入元素放入该位置* 5. 重复直至所有元素排序完成*/public static void insertSort(int[] array) {// 遍历所有待插入元素(0号元素默认有序,从0开始也可兼容)for (int i = 0; i < array.length; i++) {int temp = array[i]; // 保存当前待插入元素int j = i - 1; // 已排序序列的最后一个元素索引// 从已排序序列末尾向前比较for (; j > 0; j--) {if (array[j] > temp) {// 已排序元素大于待插入元素,向后移动一位array[j + 1] = array[j];} else {// 找到合适位置,插入元素并退出循环array[j + 1] = temp;break;}}// 若已排序序列所有元素都大于待插入元素,插入到最前端array[j + 1] = temp;}}
}
2. 希尔排序(缩小增量排序)

算法介绍:希尔排序是直接插入排序的优化版本,通过 "增量 gap" 将数组分组,对每组执行插入排序,逐步缩小 gap(通常每次减半),最终当 gap=1 时完成最后一次插入排序。目的是提前消除元素的 "远距离逆序",提高效率。

public class Sort1 {/*** 希尔排序(主方法)* 步骤:* 1. 初始化gap为数组长度,每次循环将gap减半* 2. 当gap>1时,按当前gap对数组进行分组插入排序* 3. 直至gap=1,完成最后一次排序后数组有序*/public static void shell(int[] array) {int gap = array.length;while (gap > 1) {gap /= 2; // 缩小增量(折半方式)shell(array, gap); // 按当前gap分组排序}}/*** 希尔排序的分组插入实现* @param gap 分组增量(组内元素下标间隔为gap)* 步骤:* 1. 从第gap个元素开始,依次作为每组的待插入元素* 2. 在组内与前一个元素(间隔gap)比较,大于待插入元素则后移gap位* 3. 找到位置后插入,重复直至组内有序*/private static void shell(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int temp = array[i]; // 保存待插入元素int j = i - gap; // 同组中前一个元素的索引// 组内从后往前比较for (; j > 0; j -= gap) {if (array[j] > temp) {// 同组前元素大于待插入元素,后移gap位array[j + gap] = array[j];} else {// 找到位置插入并退出array[j + gap] = temp;break;}}// 组内所有元素都大,插入到组内最前端array[j + gap] = temp;}}
}

二、选择排序类

1. 简单选择排序

算法介绍:简单选择排序的核心是 "选最值",每次从待排序区间中找到最小元素,与区间的第一个元素交换,然后缩小待排序区间,重复直至整个数组有序。

public class Sort1 {/*** 简单选择排序* 步骤:* 1. 遍历数组,每次以当前索引为待排序区间的起点* 2. 在待排序区间中寻找最小元素的索引* 3. 将最小元素与待排序区间的第一个元素交换* 4. 缩小待排序区间(起点后移),重复直至排序完成*/public static void selectSort2(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i; // 记录最小元素索引(初始为区间起点)// 寻找待排序区间的最小元素for (int j = i + 1; j < array.length; j++) {if (array[j] < array[minIndex]) {minIndex = j; // 更新最小索引}}// 交换最小元素与区间起点swap(array, i, minIndex);}}/*** 交换数组中两个元素的工具方法*/private static void swap(int[] array, int i, int j) {int temp = array[i];array[i] = array[j];array[j] = temp;}
}
2. 双向选择排序(优化版选择排序)

算法介绍:双向选择排序是简单选择排序的优化,每次同时寻找待排序区间的最小值和最大值,将最小值放到区间左端,最大值放到区间右端,同时缩小左右区间,减少遍历次数。

public class Sort1 {/*** 双向选择排序* 步骤:* 1. 初始化左右边界(left=0,right=数组末尾)* 2. 在[left, right]区间内同时寻找最小和最大元素的索引* 3. 将最小值与left位置交换,最大值与right位置交换* 4. 缩小区间(left++,right--),重复直至left >= right* 注意:若最大值初始在left位置,交换后需更新最大值索引*/public static void selectSort(int[] array) {int left = 0;int right = array.length - 1;while (left < right) {int minIndex = left; // 最小值索引(初始左边界)int maxIndex = right; // 最大值索引(初始右边界)// 遍历区间寻找最值索引for (int i = left + 1; i < right; i++) {if (array[i] < array[minIndex]) {minIndex = i; // 更新最小值索引}if (array[i] > array[maxIndex]) {maxIndex = i; // 更新最大值索引}}// 最小值交换到左边界swap(array, left, minIndex);// 若最大值原本在左边界,交换后需更新maxIndexif (maxIndex == left) {maxIndex = minIndex;}// 最大值交换到右边界swap(array, right, maxIndex);// 缩小待排序区间left++;right--;}}// 交换方法同简单选择排序,此处省略(复用上文swap)
}

三、交换排序类

1. 冒泡排序

算法介绍:冒泡排序通过相邻元素的比较和交换,使最大元素逐步 "冒泡" 到数组末尾。每轮遍历后,待排序区间的最大元素会被排到正确位置,同时通过标记是否交换优化,若某轮无交换则说明数组已有序。

public class Sort1 {/*** 冒泡排序* 步骤:* 1. 外层循环控制排序轮次(n个元素需n-1轮)* 2. 内层循环遍历待排序区间(0到n-1-i,i为已排序元素数)* 3. 相邻元素比较,前大后小则交换,标记发生交换* 4. 若某轮无交换,说明数组已有序,直接退出* 特性:时间复杂度O(N²),空间O(1),稳定排序*/public static void bubbleSort(int[] array) {for (int i = 0; i < array.length - 1; i++) {boolean flag = false; // 标记本轮是否交换// 遍历当前待排序区间for (int j = 0; j < array.length - 1 - i; j++) {if (array[j] > array[j + 1]) {swap(array, j, j + 1); // 交换相邻元素flag = true; // 标记交换}}// 无交换说明有序,提前退出if (!flag) {break;}}}// 交换方法同前,此处省略
}
2. 快速排序

算法介绍:快速排序采用 "分治" 思想,选择一个基准元素,通过分区操作将数组分为两部分(左部分≤基准,右部分≥基准),然后递归对两部分排序。核心是分区操作,以下实现两种分区方式:左右指针法和挖坑法。

public class Sort1 {/*** 快速排序(主方法)* 步骤:* 1. 从数组整体开始,调用递归方法排序* 2. 递归终止条件:子数组起始索引≥结束索引*/public static void quickSort(int[] array) {quick(array, 0, array.length - 1);}/*** 快速排序递归实现* @param start 子数组起始索引* @param end 子数组结束索引* 步骤:* 1. 若子数组长度≤1,直接返回* 2. 执行分区操作,获取基准元素的最终位置* 3. 递归排序基准左侧和右侧的子数组*/public static void quick(int[] array, int start, int end) {if (start >= end) {return;}int pivot = partition(array, start, end); // 分区(左右指针法)// int pivot = partition2(array, start, end); // 可选:挖坑法分区quick(array, start, pivot - 1); // 排序左分区quick(array, pivot + 1, end); // 排序右分区}/*** 分区操作(左右指针法)* @return 基准元素的最终索引* 步骤:* 1. 选择左边界元素作为基准,记录初始位置* 2. 右指针左移找小于基准的元素,左指针右移找大于基准的元素* 3. 交换左右指针元素,重复直至指针相遇* 4. 将基准元素放到指针相遇位置,返回该索引*/private static int partition(int[] array, int left, int right) {int temp = array[left]; // 基准元素int tempLeft = left; // 基准初始位置while (left < right) {// 右指针左移:找小于基准的元素while (left < right && array[right] >= temp) {right--;}// 左指针右移:找大于基准的元素while (left < right && array[left] <= temp) {left++;}swap(array, left, right); // 交换左右元素}swap(array, left, tempLeft); // 基准放到最终位置return left;}/*** 分区操作(挖坑法)* 步骤:* 1. 取左边界元素为基准,形成初始"坑"* 2. 右指针左移找小于基准的元素,填入左坑,右指针位置成新坑* 3. 左指针右移找大于基准的元素,填入右坑,左指针位置成新坑* 4. 重复直至指针相遇,将基准填入最后一个坑*/private static int partition2(int[] array, int left, int right) {int temp = array[left]; // 基准元素(初始坑)while (left < right) {// 右指针左移填左坑while (left < right && array[right] >= temp) {right--;}array[left] = array[right];// 左指针右移填右坑while (left < right && array[left] <= temp) {left++;}array[right] = array[left];}array[left] = temp; // 基准填最后一个坑return left;}// 交换方法同前,此处省略
}

四、堆排序

算法介绍:堆排序利用 "大根堆"(父节点≥子节点)的特性,通过构建大根堆、提取堆顶最大值并调整堆结构实现排序。步骤包括:构建初始大根堆、反复提取最大值并调整堆,最终得到有序数组。

public class Sort1 {/*** 堆排序* 步骤:* 1. 构建大根堆:从最后一个非叶子节点向前调整所有节点* 2. 提取最大值:交换堆顶(最大值)与堆尾元素,缩小堆范围* 3. 调整堆:对新堆顶执行调整操作,使其重新成为大根堆* 4. 重复步骤2-3,直至所有元素排序完成* 特性:时间复杂度O(NlogN),空间O(1),不稳定排序*/public static void heapSort(int[] array) {// 1. 构建大根堆(最后一个非叶子节点索引:array.length/2 - 1)for (int i = array.length / 2 - 1; i >= 0; i--) {adjustHeap(array, i, array.length);}// 2. 提取最大值并调整堆for (int i = array.length - 1; i > 0; i--) {swap(array, 0, i); // 堆顶(最大)与堆尾交换adjustHeap(array, 0, i); // 调整剩余元素为大根堆}}/*** 调整堆为大根堆* @param parent 待调整的父节点索引* @param heapSize 当前堆的大小(元素个数)* 步骤:* 1. 保存父节点值,初始左孩子为调整起点* 2. 比较左右孩子,找到最大子节点* 3. 若父节点小于最大子节点,交换并继续调整下一层* 4. 最终将初始父节点值放到正确位置*/private static void adjustHeap(int[] array, int parent, int heapSize) {int temp = array[parent]; // 保存父节点值int child = 2 * parent + 1; // 左孩子索引(2*parent+1)while (child < heapSize) {// 右孩子存在且更大,指向右孩子if (child + 1 < heapSize && array[child] < array[child + 1]) {child++;}// 父节点≥最大子节点,无需调整if (temp >= array[child]) {break;}// 最大子节点值赋给父节点array[parent] = array[child];// 继续调整下一层parent = child;child = 2 * parent + 1;}array[parent] = temp; // 初始父节点值放到最终位置}// 交换方法同前,此处省略
}

五,案例混合代码

public class Sort1 {// ========================= 一、插入排序类 =========================/*** 直接插入排序* 核心思想:将待排序元素逐个插入已排序序列的合适位置* 步骤:* 1. 默认第0号元素为已排序序列* 2. 依次取后续元素作为待插入元素,保存其值* 3. 与已排序序列从后往前比较,大于待插入元素则后移* 4. 找到位置后插入,重复直至所有元素有序*/public static void insertSort(int[] array) {for (int i = 0; i < array.length; i++) {int temp = array[i]; // 保存待插入元素int j = i - 1; // 已排序序列末尾索引// 从已排序序列尾部向前比较for (; j > 0; j--) {if (array[j] > temp) {array[j + 1] = array[j]; // 已排序元素后移} else {array[j + 1] = temp; // 插入元素并退出break;}}array[j + 1] = temp; // 插入到序列最前端(当所有元素都大于待插入元素时)}}/*** 希尔排序(缩小增量排序)- 直接插入排序优化版* 核心思想:按增量分组插入排序,逐步缩小增量至1* 步骤:* 1. 初始化增量gap为数组长度,每次减半* 2. 按gap分组,每组内执行插入排序* 3. gap=1时完成最后一次排序,数组有序*/public static void shellSort(int[] array) {int gap = array.length;while (gap > 1) {gap /= 2; // 缩小增量shellInsert(array, gap); // 分组插入排序}}/*** 希尔排序的分组插入实现* @param gap 分组增量(组内元素下标间隔)*/private static void shellInsert(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int temp = array[i]; // 保存待插入元素int j = i - gap; // 同组前一个元素索引// 组内从后往前比较for (; j > 0; j -= gap) {if (array[j] > temp) {array[j + gap] = array[j]; // 同组元素后移gap位} else {array[j + gap] = temp; // 插入元素并退出break;}}array[j + gap] = temp; // 插入到组内最前端}}// ========================= 二、选择排序类 =========================/*** 简单选择排序* 核心思想:每次选择待排序区间的最小值,与区间首位交换* 步骤:* 1. 遍历数组,以当前索引为待排序区间起点* 2. 寻找区间内最小值索引* 3. 交换最小值与区间首位,缩小区间,重复直至有序*/public static void selectSortSimple(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i; // 最小值索引(初始为区间起点)// 寻找待排序区间的最小值for (int j = i + 1; j < array.length; j++) {if (array[j] < array[minIndex]) {minIndex = j; // 更新最小值索引}}swap(array, i, minIndex); // 交换最小值与区间起点}}/*** 双向选择排序(优化版选择排序)* 核心思想:同时选择区间的最小值和最大值,分别放到区间两端* 步骤:* 1. 初始化左右边界,遍历区间寻找最值索引* 2. 最小值放左边界,最大值放右边界* 3. 缩小区间,重复直至左右边界相遇*/public static void selectSortDouble(int[] array) {int left = 0;int right = array.length - 1;while (left < right) {int minIndex = left; // 最小值索引(初始左边界)int maxIndex = right; // 最大值索引(初始右边界)// 遍历区间寻找最值for (int i = left + 1; i < right; i++) {if (array[i] < array[minIndex]) minIndex = i;if (array[i] > array[maxIndex]) maxIndex = i;}swap(array, left, minIndex); // 最小值交换到左边界// 若最大值原本在左边界,交换后需更新maxIndexif (maxIndex == left) maxIndex = minIndex;swap(array, right, maxIndex); // 最大值交换到右边界left++; // 缩小区间right--;}}// ========================= 三、交换排序类 =========================/*** 冒泡排序* 核心思想:相邻元素比较交换,使最大值逐步"冒泡"到尾部* 优化:无交换时说明数组有序,直接退出* 特性:时间复杂度O(N²),空间O(1),稳定排序*/public static void bubbleSort(int[] array) {for (int i = 0; i < array.length - 1; i++) {boolean isSwapped = false; // 标记本轮是否交换// 遍历待排序区间(排除已排序的尾部元素)for (int j = 0; j < array.length - 1 - i; j++) {if (array[j] > array[j + 1]) {swap(array, j, j + 1); // 交换相邻元素isSwapped = true;}}if (!isSwapped) break; // 无交换则有序,提前退出}}/*** 快速排序(分治思想)* 核心思想:选择基准分区,递归排序左右子数组* 特性:平均时间O(NlogN),最坏O(N²),空间O(logN),不稳定排序*/public static void quickSort(int[] array) {quickSortRecursive(array, 0, array.length - 1);}/*** 快速排序递归实现* @param start 子数组起始索引* @param end 子数组结束索引*/private static void quickSortRecursive(int[] array, int start, int end) {if (start >= end) return; // 子数组长度≤1时终止// 分区操作(可选:partition左右指针法 / partitionHole挖坑法)int pivotIndex = partition(array, start, end);// int pivotIndex = partitionHole(array, start, end);quickSortRecursive(array, start, pivotIndex - 1); // 排序左分区quickSortRecursive(array, pivotIndex + 1, end); // 排序右分区}/*** 快速排序分区(左右指针法)* @return 基准元素的最终索引*/private static int partition(int[] array, int left, int right) {int pivot = array[left]; // 选择左边界为基准int pivotOrigin = left; // 记录基准初始位置while (left < right) {// 右指针左移:找小于基准的元素while (left < right && array[right] >= pivot) right--;// 左指针右移:找大于基准的元素while (left < right && array[left] <= pivot) left++;swap(array, left, right); // 交换左右元素}swap(array, left, pivotOrigin); // 基准放到最终位置return left;}/*** 快速排序分区(挖坑法)* @return 基准元素的最终索引*/private static int partitionHole(int[] array, int left, int right) {int pivot = array[left]; // 基准元素(初始坑)while (left < right) {// 右指针左移填左坑while (left < right && array[right] >= pivot) right--;array[left] = array[right];// 左指针右移填右坑while (left < right && array[left] <= pivot) left++;array[right] = array[left];}array[left] = pivot; // 基准填最后一个坑return left;}// ========================= 四、堆排序 =========================/*** 堆排序(基于大根堆)* 核心思想:构建大根堆,提取堆顶最大值并调整堆* 特性:时间复杂度O(NlogN),空间O(1),不稳定排序*/public static void heapSort(int[] array) {// 1. 构建大根堆(从最后一个非叶子节点向前调整)for (int i = array.length / 2 - 1; i >= 0; i--) {adjustHeap(array, i, array.length);}// 2. 提取堆顶最大值并调整堆for (int i = array.length - 1; i > 0; i--) {swap(array, 0, i); // 堆顶(最大)与堆尾交换adjustHeap(array, 0, i); // 调整剩余元素为大根堆}}/*** 调整堆为大根堆* @param parent 待调整的父节点索引* @param heapSize 当前堆的大小*/private static void adjustHeap(int[] array, int parent, int heapSize) {int temp = array[parent]; // 保存父节点值int child = 2 * parent + 1; // 左孩子索引while (child < heapSize) {// 右孩子存在且更大,指向右孩子if (child + 1 < heapSize && array[child] < array[child + 1]) {child++;}// 父节点≥最大子节点,无需调整if (temp >= array[child]) break;array[parent] = array[child]; // 最大子节点值赋给父节点parent = child; // 继续调整下一层child = 2 * parent + 1;}array[parent] = temp; // 初始父节点值放到最终位置}// ========================= 工具方法 =========================/*** 交换数组中两个元素的工具方法* @param array 目标数组* @param i 第一个元素索引* @param j 第二个元素索引*/private static void swap(int[] array, int i, int j) {int temp = array[i];array[i] = array[j];array[j] = temp;}
}

http://www.dtcms.com/a/579182.html

相关文章:

  • 自己网站可以加标志吗金华职院优质校建设网站
  • 公司网站建设推广方案模板成都微网站系统
  • 知识体系(三)RAG
  • 网站建设关键词排名优化wordpress 树状目录
  • 教育培训网站开发做vip兼职设计师的网站有哪些
  • 嵌入式系统内存管理优化指南
  • wordpress 苏醒荆门seo
  • 湖南营销型企业网站开发怎么利用QQ空间给网站做排名
  • 网站广告模板代码手机制作视频教程
  • 小企业建站系统WordPress禁用f12
  • 西安市住房和城乡建设局官方网站做美食软件的视频网站
  • 什么是RESTful API?如何测试?
  • 做哪些网站流量最大开发网站现实网络传输失败
  • 茂名做网站报价搭建电商网站
  • c语言网站开发wordpress做直播网站吗
  • 网站做内嵌整木全屋定制十大名牌
  • 广州外贸网站公司anker 网站建设
  • 如何申请单位邮箱怎么做优化网站排名
  • 温州产品推广网站网页制作免费网站
  • 官学商大跨界 · 产学研大综合:融智学新范式应用体系
  • 太原市网站建设wordpress主题开发培训
  • 十堰建设银行官方网站app官方网站
  • 模板网站多少钱一个厦门茶叶公司 网站建设
  • 如何建立网站平台的步骤旅游做的视频网站
  • 解决Python错误0xC0000135的7个关键步骤
  • iis6.0如何做网站301电子商城网站建设
  • 郴州网站优化沧州网站推广
  • 称多网站建设石排东莞网站建设
  • 【排查了一天的坑】Flowable 监听器切换数据源失败(附详细排查过程)
  • 网站排名易下拉稳定网页在线制作图片