
本文深入探讨了python快速排序算法的正确实现,重点分析了在分区(partitioning)过程中常见的逻辑错误,如交换操作的缩进问题、支点(pivot)的最终位置确定以及递归调用边界的设置。通过详细的代码示例和修正,旨在帮助开发者理解并构建一个健壮、高效的快速排序算法。
快速排序(Quick Sort)是一种高效的、基于分治策略的排序算法。其核心思想是:
当子数组只有一个元素或为空时,递归停止。
在实现快速排序时,尤其是在分区逻辑部分,开发者常常会遇到一些细微但关键的错误,导致排序结果不正确。下面我们将结合一个常见的错误示例,分析并给出正确的实现。
原始代码中的问题分析
立即学习“Python免费学习笔记(深入)”;
考虑以下一个尝试实现快速排序的Python代码片段:
class QuickSort:
def quickSort(self, list, low, high):
if (low >= high):
return
else:
leftPointer = low
rightPointer = high
pivot = list[high]
while (leftPointer < rightPointer):
while (leftPointer < rightPointer and list[leftPointer] < pivot):
leftPointer += 1
while (leftPointer < rightPointer and list[rightPointer] > pivot):
rightPointer -= 1
list[leftPointer], list[rightPointer] = list[rightPointer], list[leftPointer] # 问题1:缩进错误
list[high], list[leftPointer] = list[leftPointer], list[high] # 问题2:支点放置逻辑错误
self.quickSort(list, low, rightPointer - 1) # 问题3:递归边界错误
self.quickSort(list, rightPointer + 1, high) # 问题3:递归边界错误
return list这段代码存在以下几个主要问题:
为了解决上述问题,我们需要对分区逻辑和支点放置策略进行调整。下面是修正后的Python快速排序实现:
class QuickSort:
def quickSort(self, input_list, low, high):
# 1. 基本情况:如果子数组只有一个元素或为空,则已排序
if low >= high:
return
# 优化:处理两个元素的子数组且已排序的情况
# 实际操作中,这个优化可以合并到low >= high的判断中,或者直接依赖后续逻辑
# if high - low == 1 and input_list[low] <= input_list[high]:
# return
# 2. 选择支点:这里选择最后一个元素作为支点
pivot = input_list[high]
# 初始化左右指针
# leftPointer从low开始寻找大于pivot的元素
# rightPointer从high-1开始寻找小于pivot的元素(不包括pivot本身)
leftPointer = low
rightPointer = high - 1
# 3. 分区过程
# 当leftPointer小于等于rightPointer时,继续进行分区
while leftPointer <= rightPointer:
# 找到第一个大于或等于pivot的元素
while leftPointer <= rightPointer and input_list[leftPointer] < pivot:
leftPointer += 1
# 找到第一个小于或等于pivot的元素
while leftPointer <= rightPointer and input_list[rightPointer] > pivot:
rightPointer -= 1
# 如果指针尚未交叉,则交换元素
if leftPointer <= rightPointer:
input_list[leftPointer], input_list[rightPointer] = input_list[rightPointer], input_list[leftPointer]
# 交换后,移动指针继续寻找
leftPointer += 1
rightPointer -= 1
# 4. 将支点放到其最终位置
# 循环结束后,leftPointer指向第一个大于等于pivot的元素的位置
# 将pivot(原位于high)与leftPointer指向的元素交换
# 这样,pivot就位于所有小于它的元素之后,所有大于它的元素之前
input_list[leftPointer], input_list[high] = input_list[high], input_list[leftPointer]
# 5. 递归排序左右子数组
# 支点现在位于leftPointer位置,所以递归范围是(low, leftPointer-1) 和 (leftPointer+1, high)
self.quickSort(input_list, low, leftPointer - 1)
self.quickSort(input_list, leftPointer + 1, high)
return input_list
修正后的关键点解释:
为了验证修正后的快速排序算法的正确性,我们可以使用不同的测试用例:
# 实例化快速排序类
quick = QuickSort()
# 测试用例1:普通乱序数组
list1 = [50, 49, 19, 4, 9]
print(f"原始数组: {list1}, 排序后: {quick.quickSort(list1, 0, len(list1) - 1)}") # 预期: [4, 9, 19, 49, 50]
# 测试用例2:已排序数组
list2 = [1, 2, 3, 4, 5]
print(f"原始数组: {list2}, 排序后: {quick.quickSort(list2, 0, len(list2) - 1)}") # 预期: [1, 2, 3, 4, 5]
# 测试用例3:逆序数组
list3 = [4, 3, 2, 1]
print(f"原始数组: {list3}, 排序后: {quick.quickSort(list3, 0, len(list3) - 1)}") # 预期: [1, 2, 3, 4]
# 测试用例4:包含重复元素的数组
list4 = [8, 6, 7, 5, 3, 0, 9, 7, 1]
print(f"原始数组: {list4}, 排序后: {quick.quickSort(list4, 0, len(list4) - 1)}") # 预期: [0, 1, 3, 5, 6, 7, 7, 8, 9]
# 测试用例5:空数组或单元素数组
list5 = []
print(f"原始数组: {list5}, 排序后: {quick.quickSort(list5, 0, len(list5) - 1) if list5 else []}") # 预期: []
list6 = [42]
print(f"原始数组: {list6}, 排序后: {quick.quickSort(list6, 0, len(list6) - 1)}") # 预期: [42]通过理解和掌握正确的快速排序分区逻辑,开发者可以避免常见的实现错误,构建出高效且可靠的排序解决方案。核心在于确保支点在每次分区后都能准确地放置在其最终位置,并且递归调用能够正确地处理左右子数组。
以上就是Python快速排序实现:常见错误与正确分区逻辑解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号