【第六篇】Java 基础排序算法:快速排序算法和堆排序 快速排序和堆排序摘要本文详细介绍了两种高效的排序算法——快速排序和堆排序。快速排序采用分治思想通过挖坑分区法实现平均时间复杂度为 O(n log n)堆排序基于完全二叉树的堆结构通过构建大顶堆和交换堆顶元素实现排序时间复杂度稳定为 O(n log n)。两种算法均为原地排序但都不稳定。快速排序(quickSort)算法核心快速排序采用区间首个元素作为基准值利用左右双指针交替移动的挖坑分区思路右指针先向左搜寻小于基准的元素填入左侧坑位再让左指针向右搜寻大于基准的元素填入右侧坑位两指针相遇时将基准放入相遇位置完成分区再通过递归分别对基准值的左右两侧子区间重复分区操作依靠分治思想逐步完成整个数组的升序排序。核心要点基准选取区间最左侧元素作为 pivot把 l 下标位置当成第一个 “坑”暂存 pivot双指针分区右指针 h 向左找小数填左坑左指针 l 向右找大数填右坑交替填坑基准归位l 与 h 相遇时只剩唯一坑位放入 pivot此时左边≤pivot、右边≥pivot递归分治以 pivot 下标分割数组分别递归排序左、右子区间直至区间只剩 1 个元素。算法步骤保存基准值pivot arr[l]循环当l h未相遇① h 往左走找到第一个小于 pivot 的元素填入 l 的坑此时 h 变为新坑② l 往右走找到第一个大于 pivot 的元素填入 h 的坑此时 l 变为新坑l h把 pivot 填入该坑返回当前下标基准最终位置递归处理左段[l, pivot下标-1]、右段[pivot下标1, h]递归终止条件区间l h无需排序直接返回。算法特点时间复杂度(O(nlog n))空间复杂度(O(log n))稳定性不稳定算法相等元素可能会改变相对位置Java语言实现packagecom.lgq.ruankao.practice;importstaticcom.lgq.ruankao.util.ArrUtil.printArr;importstaticcom.lgq.ruankao.util.ArrUtil.swap;/** * author lgq * email * date 2026/8/13 9:35 */publicclassMain3{publicstaticvoidquickSort(int[]arr,intl,inth){if(lh)return;// 获取基准值pivot在序列中分割后的下标(经过一次快速排序后pivot的下标)intpivotIndexpartition(arr,l,h);// 分治思想递归排序左区间quickSort(arr,l,pivotIndex-1);quickSort(arr,pivotIndex1,h);}// 分区函数选取最右边元素作为基准值划分大小区域// 简单说就是选择最右边元素作为基准值进行一趟快速排序最后将pivot值的下标返回privatestaticintpartition(int[]arr,intl,inth){// 选取第一个元素作为基准值intpivotarr[l];while(lh){// 1. 右指针h向左找小于pivot的元素找到就交换l和h指针指向的元素while(lharr[h]pivot){h--;}// 退出while循环表示找到了此时需要将右边的值赋值给左边覆盖掉左边的值arr[l]arr[h];// 2. 左指针l向右寻找大于pivot的数while(lharr[l]pivot){l;}// 找到大于pivot的元素了此时需要将左边的值赋值给右边覆盖掉右边的值arr[h]arr[l];}// 最后当l h时此时就是基准值pivot在一趟快速排序后的最终位置下标了进行赋值即可。arr[l]pivot;// 或者因为此时arr[l] arr[h]// arr[h] pivot;returnl;}// 测试publicstaticvoidmain(String[]args){int[]arr{5,2,9,3,7,6,1,8,4};System.out.println(排序前);printArr(arr);quickSort(arr,0,arr.length-1);System.out.println(排序后);printArr(arr);}}交换和打印函数packagecom.lgq.ruankao.util;/** * author lgq * email * date 2026/8/12 9:34 */publicclassArrUtil{publicstaticvoidprintArr(int[]arr){if(arrnull||arr.length1){return;}for(inti0;iarr.length;i){System.out.print(arr[i] );}System.out.println();}// 交换a和b的值publicstaticvoidswap(int[]arr,inti,intj){inttemparr[i];arr[i]arr[j];arr[j]temp;}}堆排序堆的定义堆是完全二叉树分为两种大顶堆每个父节点值 ≥ 左右子节点值堆顶是整个序列最大值。小顶堆每个父节点值 ≤ 左右子节点值堆顶是整个序列最小值。一般堆排序默认使用大顶堆实现升序排序。算法的核心思想将无序数组构建成大顶堆此时堆顶数组第一个元素是最大值。把堆顶最大值和数组末尾元素交换最大值落到有序末尾。对剩余未排序部分重新调整为大顶堆重复交换堆顶与末尾。不断缩小区间直到整个数组有序。算法特点时间复杂度最好 /最坏 / 平均均为 (O(nlog n))空间复杂度(O(1))原地排序不稳定排序相等元素相对位置会改变数组与堆节点下标关系设父节点下标为i左孩子2*i 1右孩子2*i 2最后一个非叶子节点⌊n/2⌋ - 1n 为数组长度Java语言编程实现packagecom.lgq.ruankao.practice;importstaticcom.lgq.ruankao.util.ArrUtil.printArr;importstaticcom.lgq.ruankao.util.ArrUtil.swap;/** * author lgq * email * date 2026/8/13 15:22 */publicclassMain4{/** * 堆调整维护大顶堆性质 * * param arr 数组 * param n 堆有效长度 * param i 当前父节点下标 */publicstaticvoidheapAdjust(int[]arr,intn,inti){intmaxValueIndexi;// 左右孩子下标intleftIndex2*i1;intrightIndex2*i2;// 判断左节点值更大if(leftIndexnarr[leftIndex]arr[maxValueIndex]){maxValueIndexleftIndex;}// 判断右节点值更大if(rightIndexnarr[rightIndex]arr[maxValueIndex]){maxValueIndexrightIndex;}// 如果最大值不是父节点就交换if(maxValueIndex!i){swap(arr,i,maxValueIndex);// 递归调整受影响的子树heapAdjust(arr,n,maxValueIndex);}}/** * 堆排序主方法升序 */publicstaticvoidheapSort(int[]arr){intnarr.length;if(n1)return;// 构造大顶堆从最后一个非叶子节点开始向前遍历for(intin/2-1;i0;i--){heapAdjust(arr,n,i);}// 逐个取出堆顶最大值放到数组末尾for(intin-1;i0;i--){swap(arr,0,i);// 调整剩余未排序区间,[0, i-1]heapJustify(arr,i,0);}}publicstaticvoidmain(String[]args){// 测试用例1普通乱序数组int[]arr1{12,11,13,5,6,7};System.out.print(排序前);printArr(arr1);heapSort(arr1);System.out.print(排序后);printArr(arr1);System.out.println(------------------------);// // 测试用例2逆序数组// int[] arr2 {9,7,5,3,1};// System.out.print(排序前);// printArr(arr2);// heapSort(arr2);// System.out.print(排序后);// printArr(arr2);// System.out.println(------------------------);//// // 测试用例3存在重复值// int[] arr3 {2,5,3,2,9,5,1};// System.out.print(排序前);// printArr(arr3);// heapSort(arr3);// System.out.print(排序后);// printArr(arr3);}}

相关新闻

最新新闻

从HBM4与Rubin展望到实战:AI开发者如何应对显存挑战与优化部署

从HBM4与Rubin展望到实战:AI开发者如何应对显存挑战与优化部署

最近在AI和图形计算领域,关于显存容量和带宽的讨论热度不减。无论是想本地部署大模型的开发者,还是追求极致游戏体验的玩家,都深刻体会到显存(Video RAM)的重要性。特别是随着大语言模型(LLM)和…

2026/8/15 11:32:41
Vim代码注释实战:从快捷键到工程思维,提升团队协作效率

Vim代码注释实战:从快捷键到工程思维,提升团队协作效率

1. 从“请欣赏”到生产力:代码注释的实战价值再审视看到“代码注释(请欣赏)”这个标题,很多程序员的第一反应可能是会心一笑,脑海里浮现出那些被精心“雕琢”过的注释——从一行简单的“// TODO: 这里以后要改”&#…

2026/8/15 11:32:41
深入解析Map文件:从链接原理到崩溃分析与内存优化实战

深入解析Map文件:从链接原理到崩溃分析与内存优化实战

1. 项目概述:从“黑盒”到“白盒”的调试利器 在嵌入式开发、逆向工程或者性能调优的深水区里摸爬滚打过的朋友,一定对“链接后程序崩溃了,但只给你一个十六进制的地址”这种场景深恶痛绝。你看着那个像天书一样的 0x0804a1b2 错误地址&…

2026/8/15 11:32:41
私有化SSL证书管理:Certd架构与实战指南

私有化SSL证书管理:Certd架构与实战指南

1. 项目概述:为什么需要私有化SSL证书管理 SSL证书管理一直是运维工作中最容易被忽视却又极其关键的环节。过去五年间,我经手过上百个因证书过期导致的线上事故,最严重的一次直接导致某电商平台支付功能瘫痪2小时,损失超过七位数。…

2026/8/15 11:32:41
Web安全实战:命令注入漏洞从入门到精通

Web安全实战:命令注入漏洞从入门到精通

命令注入漏洞完全实战教程 前置要求:已搭建 Kali Burp Suite Professional,了解 HTTP 请求基础 实验环境:PortSwigger Web Security Academy 目录 前置知识:什么是命令注入实验环境准备Lab 1:简单命令注入&#xff0…

2026/8/15 11:32:41
Android SDK开发与打包全流程:从设计到发布的工程实践

Android SDK开发与打包全流程:从设计到发布的工程实践

1. 项目概述:从使用者到创造者的视角转变 作为一名Android开发者,我们每天都在与各种SDK打交道,从Google官方的Support库、Play Services,到各大厂商的支付、推送、地图SDK。我们熟练地在 build.gradle 文件中添加一行 impleme…

2026/8/15 11:27:41