154 lines
4.4 KiB
Markdown
154 lines
4.4 KiB
Markdown
|
## 实验报告
|
|||
|
|
|||
|
### **实验1:归并排序和快速排序**
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **一、实验目的**
|
|||
|
1. 了解归并排序的基本原理;
|
|||
|
2. 掌握快速排序的基本概念及实现方法;
|
|||
|
3. 熟悉分治法的策略及其在排序算法中的应用。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **二、实验环境**
|
|||
|
1. **操作系统**:Windows 10 或 Linux;
|
|||
|
2. **编程语言**:Python 3.x;
|
|||
|
3. **开发工具**:Jupyter Notebook 或 PyCharm。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **三、实验内容**
|
|||
|
1. 实现归并排序算法;
|
|||
|
2. 实现快速排序算法;
|
|||
|
3. 对两个算法进行时间复杂度和空间复杂度分析;
|
|||
|
4. 测试并记录实验结果。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **四、实验步骤**
|
|||
|
|
|||
|
#### **1. 归并排序代码实现**
|
|||
|
|
|||
|
```python
|
|||
|
def merge_sort(arr):
|
|||
|
if len(arr) <= 1: # 递归终止条件
|
|||
|
return arr
|
|||
|
|
|||
|
mid = len(arr) // 2 # 找到中间点
|
|||
|
left_half = merge_sort(arr[:mid]) # 对左半部分递归调用
|
|||
|
right_half = merge_sort(arr[mid:]) # 对右半部分递归调用
|
|||
|
|
|||
|
return merge(left_half, right_half) # 合并已排序的两部分
|
|||
|
|
|||
|
def merge(left, right):
|
|||
|
result = []
|
|||
|
i = j = 0
|
|||
|
|
|||
|
while i < len(left) and j < len(right): # 比较并合并两部分
|
|||
|
if left[i] <= right[j]:
|
|||
|
result.append(left[i])
|
|||
|
i += 1
|
|||
|
else:
|
|||
|
result.append(right[j])
|
|||
|
j += 1
|
|||
|
|
|||
|
result.extend(left[i:]) # 添加剩余部分
|
|||
|
result.extend(right[j:])
|
|||
|
return result
|
|||
|
```
|
|||
|
|
|||
|
#### **2. 快速排序代码实现**
|
|||
|
|
|||
|
```python
|
|||
|
def quick_sort(arr):
|
|||
|
if len(arr) <= 1: # 递归终止条件
|
|||
|
return arr
|
|||
|
|
|||
|
pivot = arr[len(arr) // 2] # 选择基准
|
|||
|
left = [x for x in arr if x < pivot] # 划分为小于基准的部分
|
|||
|
middle = [x for x in arr if x == pivot] # 等于基准的部分
|
|||
|
right = [x for x in arr if x > pivot] # 大于基准的部分
|
|||
|
|
|||
|
return quick_sort(left) + middle + quick_sort(right) # 递归排序并拼接结果
|
|||
|
```
|
|||
|
|
|||
|
#### **3. 测试代码**
|
|||
|
|
|||
|
```python
|
|||
|
if __name__ == "__main__":
|
|||
|
import random
|
|||
|
|
|||
|
test_array = [random.randint(0, 100) for _ in range(10)] # 随机生成测试数据
|
|||
|
print("原始数组:", test_array)
|
|||
|
|
|||
|
sorted_array_merge = merge_sort(test_array) # 测试归并排序
|
|||
|
print("归并排序结果:", sorted_array_merge)
|
|||
|
|
|||
|
sorted_array_quick = quick_sort(test_array) # 测试快速排序
|
|||
|
print("快速排序结果:", sorted_array_quick)
|
|||
|
```
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **五、实验结果**
|
|||
|
|
|||
|
#### **运行结果截图**
|
|||
|
|
|||
|
运行代码后,生成的输出示例为:
|
|||
|
|
|||
|
```
|
|||
|
原始数组: [35, 20, 7, 85, 50, 13, 99, 42, 15, 68]
|
|||
|
归并排序结果: [7, 13, 15, 20, 35, 42, 50, 68, 85, 99]
|
|||
|
快速排序结果: [7, 13, 15, 20, 35, 42, 50, 68, 85, 99]
|
|||
|
```
|
|||
|
|
|||
|
截图展示运行前后的数组对比,验证算法的正确性。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **六、算法分析**
|
|||
|
|
|||
|
#### **1. 归并排序分析**
|
|||
|
|
|||
|
- **时间复杂度**:
|
|||
|
- 分割数组的时间复杂度为 \(O(\log n)\)。
|
|||
|
- 合并操作的时间复杂度为 \(O(n)\)。
|
|||
|
- 总时间复杂度为 \(O(n \log n)\)。
|
|||
|
- **空间复杂度**:
|
|||
|
- 需要额外的临时数组来存储中间结果,空间复杂度为 \(O(n)\)。
|
|||
|
- **稳定性**:
|
|||
|
- 归并排序是稳定的,因为在合并时保持了元素的相对顺序。
|
|||
|
|
|||
|
#### **2. 快速排序分析**
|
|||
|
|
|||
|
- **时间复杂度**:
|
|||
|
- 平均情况:每次划分数组为两部分,时间复杂度为 \(O(n \log n)\)。
|
|||
|
- 最坏情况:当划分极不均匀时,时间复杂度为 \(O(n^2)\)。
|
|||
|
- **空间复杂度**:
|
|||
|
- 原地排序,不需要额外的存储空间,空间复杂度为 \(O(\log n)\)(递归栈空间)。
|
|||
|
- **稳定性**:
|
|||
|
- 快速排序是不稳定的,因为在分区时元素的相对顺序可能会改变。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **七、实验总结**
|
|||
|
|
|||
|
1. **实验收获**:
|
|||
|
- 理解了分治法的基本思想,并能将其应用于排序算法中。
|
|||
|
- 掌握了归并排序和快速排序的代码实现及其优化方法。
|
|||
|
- 理解了两种算法在不同场景下的性能优劣。
|
|||
|
|
|||
|
2. **两种算法对比**:
|
|||
|
- 归并排序适合需要稳定排序且对内存消耗不敏感的场景。
|
|||
|
- 快速排序适合对时间要求较高且数据量较大的场景,但对最坏情况的优化尤为重要。
|
|||
|
|
|||
|
3. **进一步优化建议**:
|
|||
|
- 快速排序可以通过随机化基准元素选择或三路划分优化最坏情况性能。
|
|||
|
- 对归并排序可使用原地合并技术降低空间复杂度。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
### **附录:完整代码**
|
|||
|
|
|||
|
将归并排序和快速排序代码整合为一个文件,附加到实验报告中以便查阅和调试。
|