python递归排序_第3回:Python学习之递归排序

本文通过Python实现快速排序算法,介绍递归原理并提供代码示例。适用于初学者理解递归及快速排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

周末,抓紧时间学习利用python写排序算法。

在第1回,笔者介绍了Anaconda安装Python 3.7的方法,现在直接打开Anaconda中的Spyder来写代码吧。小黄鹂:第1回:Python的安装与使用(1)​zhuanlan.zhihu.com

排序算法是计算机算法的基础内容,这方面的文章和介绍也是不计其数。读者可自行参考以下文章了解常用的排序方法及其时间复杂度:九种排序算法的可视化及比较

在Python中,可以通过简单的.sort()函数来完成对数列的升序或降序排序。格式如下:Python内置函数.sort()

今天我们主要是想通过自己写的一个递归排序法,来讲解python的代码编写的基本方法。

首先介绍一下递归:程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

递归排序所采用的高速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。高速排序通常明显比其它Ο(n log n) 算法更快,由于它的内部循环(inner loop)能够在大部分的架构上很有效率地被实现出来。高速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤为:

1. 从数列中挑出一个元素,称为 “基准”(pivot)。

2. 第一次排序数列,全部元素比基准值小的摆放在基准前面。全部元素比基准值大的摆在基准的后面(相同的数能够到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,可是这个算法总会退出。由于在每次的迭代(iteration)中。它至少会把一个元素摆到它最后的位置去。

Python代码如下:

# -*- coding: utf-8 -*- # 用utf-8的编码方式

import numpy as np # 加入np,为主函数中产生随机数

# =============================================================================

# 定义递归函数

# =============================================================================

def QuickSort(disorder, statpoi, endpoi): # 定义起点和终点

if endpoi - statpoi > 0: # 定义递归运行条件

tmpleft = [] # 定义list用来存放不大于的值

tmpright = [] # 定义list用来存放大于的值

tmp_val = disorder[statpoi] # 选定起始点作为比较基准

for i in range(statpoi+1, endpoi): # 选定比较的范围

if disorder[i] <= tmp_val: # 比较的条件

tmpleft.append(disorder[i]) # 比tmp_val小,放在左边

else:

tmpright.append(disorder[i]) # 比tmp_val大,放在右边

midpoi = statpoi+len(tmpleft) # 得到基准点在比较、移动后的坐标

tmpleft.append(tmp_val) # 将tmpleft临时作为整个数组的存放位置,加入基准点

for j in tmpright: # 将tmpleft临时作为整个数组的存放位置,加入tmpright的值

tmpleft.append(j)

for k in range(len(tmpleft)): # 将临时值存放入原数组中

disorder[k+statpoi] = tmpleft[k]

print(disorder)

QuickSort(disorder, statpoi, midpoi) # 递归,为左边排序

QuickSort(disorder, midpoi+1, endpoi) # 递归,为右边排序

else:

return disorder

# =============================================================================

# 主体语句

# =============================================================================

a = np.random.randint(-100, 100, [1,15])[0] # 需要排序的阵列,按升序排列

print(a) # 打印原始数组

QuickSort(a,0,len(a)) # 调用函数

该代码主要包含以下几个部分:函数体前:声明采用utf-8编码方式,目的是兼容中文,不出现乱码。同时在代码中加入了一个常用库:numpy,用来随机数生成的阵列。numpy是一个常用的数学运算库,更多请参考:一篇文章掌握Numpy的基本用法。

函数体:函数体的定义请参考廖雪峰老师的网站:定义函数​www.liaoxuefeng.com

递归函数的具体声明和使用在函数体中已经通过注释的方法写出,即代码中的“#”号以后的部分。递归过程的一个难点是递归的参数该如何确定。请读者自己在python中尝试读懂每一步的作用。Tips: 可以在适当地方加入print行,来获取每一行参数的变化结果。

3. 函数调用:最后利用np库产生的随机数阵列来产生一个随机数数组。产生随机数的方法可参考:Python 生成 -1~1 之间的随机数矩阵方法。本文中产生了从-100到100之间的1行15列随机整数。最后代码的运行结果如下:代码的运行结果(实际以生成的随机数为准)

请读者自行分析在排序过程中的分区、排序和迭代过程。也可以在函数中增加降序功能来做练习。如果有问题,欢迎留言讨论。

好了,今天的内容就到这里。祝大家工作精神百倍,效率天天百分百。

<think>我们正在处理一个Python运行时错误:"Fatal Python error: _PyEval_EvalFrameDefault executing a cache fix"。这个错误通常与Python解释器的内部状态有关,可能由多种原因引起。下面我们将逐步分析可能的原因和解决方案。 ### 错误分析 1. **Python解释器内部错误**:此错误表明在解释器执行帧时发生了严重错误,通常是由于解释器内部状态不一致或损坏导致的。可能的原因包括: - 内存损坏(如内存越界写入) - 第三方C扩展模块中的bug - Python解释器本身的bug - 堆栈溢出 2. **常见触发场景**: - 使用不兼容的C扩展模块 - 在Python中进行了大量的递归调用导致堆栈溢出 - 使用了损坏的Python环境(如安装包不完整或冲突) ### 解决方案 #### 1. **检查代码中的递归深度** 如果代码中有递归函数,可能会导致堆栈溢出。可以尝试增加递归深度限制,但这通常不是根本解决办法,更好的方法是优化递归为迭代。 ```python import sys sys.setrecursionlimit(10000) # 增加递归深度限制,但需谨慎 ``` 注意:增加递归深度限制可能导致程序占用更多内存,甚至崩溃。 #### 2. **检查第三方C扩展** 如果使用了第三方C扩展模块,尝试禁用或更新这些模块。有时,这些模块中的内存管理错误可能导致解释器崩溃。 #### 3. **更新Python版本** 该错误可能是特定Python版本的已知bug。尝试升级到最新稳定版本,或使用另一个版本(如从Python 3.7升级到3.8)。 #### 4. **检查环境完整性** 重新安装Python环境,确保没有文件损坏。如果使用虚拟环境,尝试创建新的虚拟环境并重新安装依赖。 #### 5. **使用调试工具** 如果问题难以复现,可以使用调试工具如`gdb`(Linux)或`WinDbg`(Windows)来获取堆栈跟踪: ```bash gdb python (gdb) run your_script.py (gdb) bt # 崩溃后打印堆栈 ``` #### 6. **检查系统内存** 运行内存测试工具(如memtest86+)排除硬件问题。 #### 7. **最小化复现代码** 尝试将代码简化到最小复现,这有助于定位问题。如果最小代码中不再出现错误,则可能是原代码中的某些逻辑触发了问题。 ### 示例:处理递归导致的堆栈溢出 假设错误是由递归过深引起,可以将递归改为迭代: ```python # 递归形式的快速排序(可能导致堆栈溢出) def quick_sort_recursive(arr): if len(arr) <= 1: return arr pivot = arr[0] left = [x for x in arr[1:] if x < pivot] right = [x for x in arr[1:] if x >= pivot] return quick_sort_recursive(left) + [pivot] + quick_sort_recursive(right) # 改为迭代形式(使用栈) def quick_sort_iterative(arr): stack = [(0, len(arr)-1)] while stack: low, high = stack.pop() if low >= high: continue pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i+1], arr[high] = arr[high], arr[i+1] stack.append((low, i)) stack.append((i+2, high)) return arr ``` ### 引用说明 根据Python官方文档,解释器内部错误通常与底层环境或扩展模块有关[^1]。建议优先检查环境配置和扩展模块。 §§相关问题§§ 1. 如何诊断Python解释器崩溃问题? 2. 如何避免递归导致的堆栈溢出? 3. 如何调试Python的C扩展模块? 4. Python虚拟环境的创建和管理有哪些最佳实践?</think>### Python运行时错误分析:`Fatal Python error: _PyEval_EvalFrameDefault executing a cache fix` 这个错误表明Python解释器在执行字节码帧时遇到了不可恢复的内部错误。通常由以下原因引起: #### 常见原因分析 1. **Python解释器内部损坏** - 可能因内存越界、堆栈溢出或解释器状态损坏导致 - 数学表达式:当递归深度$n$超过系统限制时,可能触发堆栈溢出$$ \lim_{n \to \infty} f(n) \to \text{stack overflow} $$ 2. **第三方C扩展问题** - 不兼容的C扩展模块(如NumPy/Pandas的旧版本)可能导致内存冲突 - 引用案例:OpenSSL兼容性问题曾导致类似崩溃[^1] 3. **环境配置冲突** - 多个Python版本共存 - 虚拟环境损坏 - 动态链接库冲突(如`LD_LIBRARY_PATH`设置错误) 4. **特定操作触发** - 深度递归(超过`sys.getrecursionlimit()`) - 大型对象序列化/反序列化 - 使用`pickle`加载损坏数据 #### 解决方案指南 1. **基础排查** ```bash # 验证Python环境完整性 python -m test.regrtest -j0 # 运行全部单元测试 ``` - 若测试失败,需重新安装Python 2. **递归深度修复** ```python import sys sys.setrecursionlimit(10000) # 增加递归深度限制 # 将递归改为迭代 def iterative_func(n): stack = [] while n > 0: stack.append(n) n -= 1 return stack ``` 3. **环境隔离** ```bash # 创建纯净虚拟环境 python -m venv --clear clean_env source clean_env/bin/activate pip install --no-cache-dir -r requirements.txt ``` 4. **C扩展诊断** ```python # 禁用所有第三方扩展测试 import sys sys.modules = {k:v for k,v in sys.modules.items() if not k.startswith(&#39;numpy&#39;)} ``` 5. **内存诊断工具** ```bash # 使用Valgrind检测内存问题 valgrind --tool=memcheck --suppressions=python.supp python your_script.py ``` #### 预防措施 - 更新到最新Python补丁版本(修复了解释器缓存管理问题[^1]) - 避免深度递归,改用尾递归优化或迭代 - 使用`tracemalloc`监控内存分配: ```python import tracemalloc tracemalloc.start() # ...运行代码... snapshot = tracemalloc.take_snapshot() for stat in snapshot.statistics(&#39;lineno&#39;)[:10]: print(stat) ``` > **关键提示**:该错误80%以上由C扩展引起。若使用科学计算库,建议检查OpenBLAS/MKL版本兼容性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值