快速排序实战:用Java手写一个高效排序工具(附完整代码)
快速排序实战用Java手写一个高效排序工具附完整代码如果你写过Java程序大概率用过Arrays.sort()或者Collections.sort()。它们用起来很方便但有时候你会好奇这个“排序”到底是怎么在幕后运作的特别是当处理的数据量很大或者数据本身有特殊结构时理解底层的排序机制不仅能帮你写出更高效的代码还能在面试和系统设计时游刃有余。今天我们不谈那些库函数就聊聊如何从零开始用Java亲手打造一个高效的快速排序工具。这不仅仅是实现一个算法更是理解如何将一个经典理论打磨成能在真实项目中稳定运行的实用组件。快速排序Quicksort的名气很大它几乎是所有算法教科书和面试的必考内容。但很多人学完之后留下的印象可能只是“分治”、“递归”和“平均O(n log n)”这几个干巴巴的概念。真正动手时面对具体的数组下标、边界条件和性能陷阱往往还是一头雾水。这篇文章的目标就是带你跨过“知道”和“会用”之间的鸿沟。我们会从一个最朴素的快速排序实现开始一步步迭代优化加入工程化的思考最终形成一个健壮、高效且易于集成的排序工具类。你会发现实现算法只是第一步让它变得“好用”和“可靠”才是更有挑战性的部分。1. 从零开始理解快速排序的核心思想在动手敲代码之前我们必须把快速排序的“心法”吃透。很多教程一上来就展示代码忽略了算法背后的直观理解这就像学武功只记招式不懂内功心法。快速排序的核心其实是一种“分而治之”的策略。想象一下你要整理书架上杂乱无章的书。一个高效的办法不是一本本去排而是先选一个“标杆”比如一本名为《Java编程思想》的书。然后把所有比它“小”比如书名首字母在J之前的书放到它的左边所有比它“大”的书放到它的右边。这样一来虽然左右两堆书内部还是乱的但《Java编程思想》这本书已经放到了它最终该在的位置上。接下来你只需要分别对左边和右边两堆书重复同样的过程即可。这个过程包含了三个关键步骤分区Partitioning这是快速排序的灵魂。选取一个元素作为“基准”pivot然后重新排列数组使得所有小于基准的元素都在其左侧所有大于基准的元素都在其右侧。基准元素自身则被放置到了其最终的正确位置。递归Recursion对基准左侧和右侧的两个子数组分别递归地应用快速排序。基线条件Base Case当子数组的长度为0或1时它自然就是有序的递归终止。这个思想听起来简单但分区操作的具体实现是决定算法效率、代码清晰度和稳定性的关键。常见的分区策略有“挖坑填数法”和“双指针交换法”。我们后续会实现并对比它们。注意快速排序是一种不稳定的排序算法。这意味着如果数组中有两个相等的元素它们在排序后的相对位置可能会改变。如果你的业务逻辑依赖排序的稳定性例如先按成绩排序再按学号排序希望成绩相同时学号顺序不变那么应该选择归并排序等稳定算法。2. 第一版实现最直观的“挖坑填数”法让我们先用最经典、最易于理解的“挖坑填数”思路写出第一个可运行的快速排序。这个方法非常形象就像在数组里挖坑和填坑。public class QuickSortV1 { /** * 快速排序的公开接口 * param arr 待排序的数组 */ public static void sort(int[] arr) { if (arr null || arr.length 1) { return; // 基线条件空数组或单元素数组无需排序 } quickSort(arr, 0, arr.length - 1); } /** * 递归进行快速排序的内部方法 * param arr 数组 * param left 当前子数组的左边界包含 * param right 当前子数组的右边界包含 */ private static void quickSort(int[] arr, int left, int right) { // 递归终止条件子数组长度小于等于1 if (left right) { return; } // 执行分区操作并获取基准值的最终位置 int pivotIndex partitionByHole(arr, left, right); // 递归排序左半部分 quickSort(arr, left, pivotIndex - 1); // 递归排序右半部分 quickSort(arr, pivotIndex 1, right); } /** * “挖坑填数”法分区 * 1. 选取最左边的元素作为基准值这个位置就形成了一个“坑”。 * 2. 从右向左找比基准小的数找到后填入左边的坑此时该数原来的位置成为新坑。 * 3. 从左向右找比基准大的数找到后填入右边的坑此时该数原来的位置成为新坑。 * 4. 重复2-3直到左右指针相遇将基准值填入最后的坑中。 * return 基准值的最终索引位置 */ private static int partitionByHole(int[] arr, int left, int right) { int pivot arr[left]; // 基准值同时arr[left]成为“坑” int i left; int j right; while (i j) { // 阶段1从右向左扫描找第一个小于pivot的元素 while (i j arr[j] pivot) { j--; } if (i j) { arr[i] arr[j]; // 将找到的小于pivot的值填入左边的“坑” i; // 填坑后i位置已就位指针右移 } // 阶段2从左向右扫描找第一个大于pivot的元素 while (i j arr[i] pivot) { i; } if (i j) { arr[j] arr[i]; // 将找到的大于pivot的值填入右边的“坑” j--; // 填坑后j位置已就位指针左移 } } // 循环结束i j这就是基准值应该放入的最终位置 arr[i] pivot; return i; } }你可以写一个简单的测试来验证它public class TestQuickSortV1 { public static void main(String[] args) { int[] testArray {3, 7, 8, 5, 2, 1, 9, 5, 4}; System.out.println(排序前: Arrays.toString(testArray)); QuickSortV1.sort(testArray); System.out.println(排序后: Arrays.toString(testArray)); } }这个版本完美地诠释了算法思想但它有几个明显的工程缺陷栈溢出风险在极端情况下比如数组已经有序或逆序递归深度会达到O(n)对于大数据量可能引发StackOverflowError。最坏情况性能同样是针对已排序或逆序数组每次分区都极不平衡一个子数组为空导致时间复杂度退化到O(n²)。基准值选择单一总是选择最左边的元素作为基准容易落入上述最坏情况。类型固定只能处理int[]通用性差。接下来我们就针对这些问题进行大刀阔斧的优化。3. 性能优化打造工业级排序工具一个玩具级的算法实现和一个能在生产环境使用的工具差别就在于对各种边界情况和性能陷阱的处理。我们的优化将围绕以下几个核心点展开。3.1 优化基准值Pivot的选择选择第一个或最后一个元素作为基准是快速排序性能的“阿喀琉斯之踵”。优化策略的核心是让基准值尽可能接近数组的中位数使得分区更平衡。策略一三数取中法这是最简单有效的优化之一。我们取子数组的左端、中间、右端三个元素将其中大小居中的那个作为基准值。private static int choosePivotIndex(int[] arr, int left, int right) { int mid left (right - left) / 2; // 防止(leftright)溢出 // 找出左、中、右三个值的中位数索引 if (arr[left] arr[mid]) { if (arr[mid] arr[right]) { return mid; } else if (arr[left] arr[right]) { return right; } else { return left; } } else { if (arr[left] arr[right]) { return left; } else if (arr[mid] arr[right]) { return right; } else { return mid; } } }在partition方法开始前我们将选出的基准值交换到left位置后续流程不变。这个小改动能极大避免对已排序数组的最坏情况。策略二随机化另一种思路是随机选择一个元素作为基准。这从概率上保证了算法期望时间复杂度为O(n log n)几乎不可能出现人为构造的最坏情况。private static int choosePivotIndexRandom(int left, int right) { return ThreadLocalRandom.current().nextInt(left, right 1); }在实际项目中三数取中法因其简单、稳定且无需随机数生成开销是更常见的选择。我们将它集成到我们的分区方法中。3.2 优化递归深度尾递归与栈模拟递归虽然优雅但深度过大会导致栈溢出。我们可以优化递归调用并考虑用迭代替代递归。尾递归优化观察我们的递归调用quickSort(arr, left, pivotIndex-1)和quickSort(arr, pivotIndex1, right)。编译器通常会对这种形式的尾递归进行优化但Java标准并未强制要求。我们可以手动进行一种“类尾递归”优化——先处理较小的那个子数组较大的子数组通过更新参数进行下一次循环处理。这能保证递归深度最多为O(log n)。private static void quickSortOptimized(int[] arr, int left, int right) { // 使用循环替代一部分递归 while (left right) { int pivotIndex partition(arr, left, right); // 总是先递归处理较短的那部分 if (pivotIndex - left right - pivotIndex) { quickSortOptimized(arr, left, pivotIndex - 1); left pivotIndex 1; // 更新左边界循环处理右半部分 } else { quickSortOptimized(arr, pivotIndex 1, right); right pivotIndex - 1; // 更新右边界循环处理左半部分 } } }显式栈模拟彻底摆脱递归使用自己维护的栈来保存待处理的子数组边界。这在理论上是完全可行的但代码会复杂不少。对于快速排序手动尾递归优化通常已足够。3.3 优化小数组排序插入排序的威力当递归到很小的子数组时比如长度小于10快速排序的递归调用开销反而会大于排序本身。一个经典的优化是当数组长度小于某个阈值时切换到插入排序。插入排序对小规模、近乎有序的数据效率很高。private static final int INSERTION_SORT_THRESHOLD 7; private static void quickSortHybrid(int[] arr, int left, int right) { // 如果区间足够小使用插入排序 if (right - left INSERTION_SORT_THRESHOLD) { insertionSort(arr, left, right); return; } int pivotIndex partition(arr, left, right); quickSortHybrid(arr, left, pivotIndex - 1); quickSortHybrid(arr, pivotIndex 1, right); } private static void insertionSort(int[] arr, int left, int right) { for (int i left 1; i right; i) { int key arr[i]; int j i - 1; while (j left arr[j] key) { arr[j 1] arr[j]; j--; } arr[j 1] key; } }3.4 实现更高效的分区双指针交换法“挖坑填数”法易懂但赋值操作较多。Lomuto分区法和Hoare分区法是两种更高效、更简洁的实现。这里我们实现经典的Hoare分区法它的交换次数通常更少。/** * Hoare分区法 * 1. 选取中间值作为基准结合了三数取中。 * 2. 两个指针分别从左右两端向中间扫描。 * 3. 左指针找大于等于基准的值右指针找小于等于基准的值。 * 4. 交换它们直到指针交错。 * 注意返回的索引不一定是基准的最终位置但保证了左边基准右边基准。 */ private static int partitionHoare(int[] arr, int left, int right) { int mid left (right - left) / 2; // 三数取中并将中位数交换到left位置作为基准 int pivotIndex medianOfThree(arr, left, mid, right); swap(arr, left, pivotIndex); int pivot arr[left]; int i left - 1; int j right 1; while (true) { // 移动左指针直到找到一个pivot的元素 do { i; } while (arr[i] pivot); // 移动右指针直到找到一个pivot的元素 do { j--; } while (arr[j] pivot); // 如果指针相遇或交错分区完成 if (i j) { return j; // 注意返回的是j它指向的是左分区的最后一个元素 } // 交换两个错位的元素 swap(arr, i, j); } } // 辅助函数交换数组中两个元素 private static void swap(int[] arr, int i, int j) { int temp arr[i]; arr[i] arr[j]; arr[j] temp; }使用Hoare分区法时递归调用的边界需要稍作调整quickSort(arr, left, pivotIndex)和quickSort(arr, pivotIndex 1, right)。4. 工程化封装构建通用的排序工具类现在我们把所有优化点整合起来并考虑更多的工程实践打造一个真正实用的工具类。4.1 支持泛型与自定义比较器一个强大的排序工具不应该只限于int类型。我们可以利用Java泛型和Comparator接口使其能够排序任何可比较的对象。public class AdvancedQuickSort { private static final int INSERTION_SORT_THRESHOLD 7; // 公开的排序方法支持泛型数组 public static T extends Comparable? super T void sort(T[] arr) { if (arr null || arr.length 1) return; quickSort(arr, 0, arr.length - 1, null); } // 公开的排序方法支持泛型数组和自定义比较器 public static T void sort(T[] arr, Comparator? super T comparator) { if (arr null || arr.length 1) return; quickSort(arr, 0, arr.length - 1, comparator); } // 内部递归排序 private static T void quickSort(T[] arr, int left, int right, Comparator? super T comparator) { // 小数组使用插入排序 if (right - left INSERTION_SORT_THRESHOLD) { insertionSort(arr, left, right, comparator); return; } // 尾递归优化循环处理大区间 while (left right) { int p partition(arr, left, right, comparator); // 递归处理较小的部分循环处理较大的部分 if (p - left right - p) { quickSort(arr, left, p - 1, comparator); left p 1; } else { quickSort(arr, p 1, right, comparator); right p - 1; } } } // 分区操作使用类似Lomuto的方法便于理解 private static T int partition(T[] arr, int left, int right, Comparator? super T comparator) { // 三数取中选取基准索引 int pivotIndex medianOfThree(arr, left, left (right-left)/2, right, comparator); swap(arr, pivotIndex, right); // 将基准放到最右边 T pivot arr[right]; int i left - 1; // 小于基准的区域的边界 for (int j left; j right; j) { if (compare(arr[j], pivot, comparator) 0) { i; swap(arr, i, j); } } swap(arr, i 1, right); // 将基准放到正确位置 return i 1; } // 三数取中法的泛型实现 private static T int medianOfThree(T[] arr, int i, int j, int k, Comparator? super T comparator) { T a arr[i], b arr[j], c arr[k]; boolean ab compare(a, b, comparator) 0; boolean ac compare(a, c, comparator) 0; boolean bc compare(b, c, comparator) 0; if (ab ^ ac) return i; // a是中位数 if ((!ab) ^ bc) return j; // b是中位数 return k; // c是中位数 } // 通用的比较方法 private static T int compare(T a, T b, Comparator? super T comparator) { if (comparator ! null) { return comparator.compare(a, b); } else { SuppressWarnings(unchecked) Comparable? super T ca (Comparable? super T) a; return ca.compareTo(b); } } // 泛型插入排序 private static T void insertionSort(T[] arr, int left, int right, Comparator? super T comparator) { for (int i left 1; i right; i) { T key arr[i]; int j i - 1; while (j left compare(arr[j], key, comparator) 0) { arr[j 1] arr[j]; j--; } arr[j 1] key; } } private static T void swap(T[] arr, int i, int j) { T temp arr[i]; arr[i] arr[j]; arr[j] temp; } }4.2 性能对比与测试为了验证我们优化后的工具是否有效可以设计一个简单的性能测试。我们对比JDK自带的Arrays.sort()针对对象数组使用TimSort针对基本类型使用双轴快速排序、我们最初的V1版本和最终的AdvancedQuickSort。import java.util.Arrays; import java.util.Random; public class PerformanceBenchmark { public static void main(String[] args) { int size 1_000_000; Integer[] testData new Integer[size]; Random rand new Random(); // 生成随机数据 for (int i 0; i size; i) { testData[i] rand.nextInt(size * 10); } Integer[] dataForJdk testData.clone(); Integer[] dataForOur testData.clone(); // 测试JDK Arrays.sort long start System.currentTimeMillis(); Arrays.sort(dataForJdk); long jdkTime System.currentTimeMillis() - start; System.out.println(JDK Arrays.sort 耗时: jdkTime ms); // 测试我们的AdvancedQuickSort start System.currentTimeMillis(); AdvancedQuickSort.sort(dataForOur); long ourTime System.currentTimeMillis() - start; System.out.println(Our AdvancedQuickSort 耗时: ourTime ms); // 验证排序正确性 boolean correct Arrays.equals(dataForJdk, dataForOur); System.out.println(排序结果是否正确: correct); } }在我的测试环境中对于百万级随机整数优化后的AdvancedQuickSort性能与Arrays.sort()处于同一数量级有时甚至略快因为Arrays.sort对对象数组用的是更复杂的TimSort。而对于已排序或包含大量重复数据的数组我们的三数取中和混合插入排序策略能有效避免性能退化。4.3 在实际项目中的应用考量手写排序工具在真实项目中何时有用虽然99%的情况你都会直接用库函数但了解其原理和实现能帮你面试与算法竞赛这是基础要求。嵌入式或特定环境在资源极其受限、无法使用完整Java标准库的环境下。教育目的用于教学或理解算法本质。定制化需求当你需要对排序过程有极端精细的控制时例如需要监控比较和交换次数或者实现一种特殊的、库函数不支持的比较逻辑。提示在绝大多数商业Java开发中强烈建议直接使用Collections.sort()或Arrays.sort()。它们是经过千锤百炼、深度优化的工业级实现考虑了稳定性、内存使用、最坏情况性能等无数细节。自己实现的排序工具更多是用于学习和理解或在非常特殊的场景下使用。5. 总结与扩展思考走到这里我们已经从一个简单的快速排序概念迭代出了一个支持泛型、拥有多种优化策略的实用工具类。这个过程本身就是一次完整的“算法工程化”实践。它告诉我们从理论算法到生产代码中间隔着对细节的无数打磨。最后再分享几个我在实践中遇到的、与排序相关的小点关于稳定性如果你需要稳定排序快速排序不是你的菜。Java中对象的Arrays.sort和Collections.sort使用的是TimSort一种归并排序和插入排序的混合体它是稳定的。对于基本类型由于稳定性无关紧要JDK使用了更快的双轴快速排序。空间复杂度我们实现的快速排序是原地排序空间复杂度主要是递归调用栈的开销平均为O(log n)最坏为O(n)。通过尾递归优化我们可以将最坏情况的空间复杂度也降到O(log n)。并行化可能快速排序的“分治”特性使其天然适合并行化。你可以使用ForkJoinPool来并发地对左右两个子数组进行排序这在多核处理器上能带来显著的性能提升。不过线程创建和管理的开销意味着数据量必须足够大才划算。面对重复元素当数组中有大量重复元素时标准的快速排序效率会降低因为分区可能不平衡。三路快速排序是解决这个问题的经典变种它将数组分为“小于”、“等于”、“大于”基准值三部分能高效处理重复元素。其核心分区循环如下所示// 三路快排分区示意 (Dutch National Flag Problem) int lt low, gt high, i low 1; T pivot arr[low]; while (i gt) { int cmp compare(arr[i], pivot, comparator); if (cmp 0) { swap(arr, lt, i); } else if (cmp 0) { swap(arr, i, gt--); } else { i; } } // 递归排序 arr[low..lt-1] 和 arr[gt1..high]实现一个完整的三路快排并集成到我们的工具类中会是另一个很好的练习。它能让你的排序工具在面对真实世界数据通常包含大量重复项时更加健壮。

相关新闻

避坑指南:天算大数据模型处理手机话单数据的5个常见错误

避坑指南:天算大数据模型处理手机话单数据的5个常见错误

避坑指南:天算大数据模型处理手机话单数据的5个常见错误 刚接触天算平台处理通信数据时,很多开发者会感觉信心满满——不就是把话单数据导进去,跑几个聚合和过滤逻辑吗?但现实往往很骨感。我见过不止一个项目,因为几个…

2026/7/7 4:35:00 阅读更多 →
一场彝文注释引发的技术灾难:全球化开发中的本地化测试盲区

一场彝文注释引发的技术灾难:全球化开发中的本地化测试盲区

当那行古老的彝文注释被编译器吞入时,整个智能编程系统像被施了咒语般开始抽搐。监控大屏上,AI总监的虚拟形象突然定格成扭曲的代码马赛克——这场精心策划的“文化融合实验”,最终以每秒37TB的异常日志流量将整个持续集成平台压垮... 一、灾…

2026/7/7 1:23:54 阅读更多 →
Python字典使库管新手找货快1000倍

Python字典使库管新手找货快1000倍

找货慢的痛点引入 在库管、新手出库中,尤其是双十一期间、促销等活动期间,传统找货一般是凭自己的经验找货,这样不仅仅导致出库效率慢、耗时长,而且还导致加班、老板赚到的利润低而导致被老板训了一顿、客户不满而导致客户流失。…

2026/7/5 15:14:18 阅读更多 →

最新新闻

为什么“双触发器”不够用?

为什么“双触发器”不够用?

FIFO / 握手 / Toggle,同步方案到底该怎么选?在前两篇里,我们已经达成了两个共识:CDC 问题一定会发生亚稳态不可避免,但可以被控制于是很多工程师会很自然地得出一个结论:“那我所有跨时钟信号都加双触发器…

2026/7/7 4:35:45 阅读更多 →
论领域驱动设计在复杂业务中台架构中的应用

论领域驱动设计在复杂业务中台架构中的应用

思维导图 精简版本 背景角色:零售全渠道订单中台(3万日单/8k TPS/8月/24人)。我任架构师,全程主导DDD落地,含事件风暴、上下文划分、四层架构、聚合建模、事件驱动与性能调优。 核心实践:①事件风暴绘时间轴,输出《术…

2026/7/7 4:31:44 阅读更多 →
10. Nginx 模块开发:Reload 时复用 Zone 数据

10. Nginx 模块开发:Reload 时复用 Zone 数据

1. 引言 在 Nginx 模块开发中,共享内存 Zone 是跨 Worker 进程共享数据的关键机制。当执行 nginx -s reload 时,旧 Master 进程会优雅退出,新 Master 进程重新加载配置并 fork 新的 Worker 进程。默认情况下,旧 Zone 的内存会随着…

2026/7/7 4:31:44 阅读更多 →
Python API自动化测试框架:从设计原理到工程实践全解析

Python API自动化测试框架:从设计原理到工程实践全解析

1. 项目概述:为什么我们需要一个自己的API自动化框架?在软件开发和测试领域,API接口自动化测试早已不是新鲜事。市面上有Postman、JMeter、RestAssured等成熟工具,开源社区也有pytest-requests、httpx等优秀的库。那么&#xff0c…

2026/7/7 4:29:44 阅读更多 →
论软件测试方法及应用

论软件测试方法及应用

论软件测试方法及应用请围绕“论软件测试方法及应用”论题,依次从以下三个方面进行论述。1.概要叙述你参与管理和开发的软件项目以及你在其中所承担的主要工作。2.说明三种静态测试方法的概念,代码审查,静态结构分析和代码质量度量。3.结合项…

2026/7/7 4:27:44 阅读更多 →
别再死磕提示词了!2026年,做小红书图文带货,聪明人都在用这套“商品工作流

别再死磕提示词了!2026年,做小红书图文带货,聪明人都在用这套“商品工作流

最近跟几个做小红书图文带货的朋友聊天,大家普遍有一种很深的无力感。不是因为不够努力,相反,大家都很拼。天天在各种群里收藏最新的 AI 提示词,追着各种新工具跑,甚至连最近流行的“循环工程”都去研究了一遍。但回到…

2026/7/7 4:25:44 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻