first commit
This commit is contained in:
35
sort_closet/code-sorting/BubbleSort.cpp
Normal file
35
sort_closet/code-sorting/BubbleSort.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* function : implement bubble sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void BubbleSort(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
bool swapped;
|
||||
for (int i = 0; i < static_cast<int>(nums.size()) - 1; i++)
|
||||
{
|
||||
swapped = false;
|
||||
for (int j = 0; j < static_cast<int>(nums.size()) - 1 - i; j++)
|
||||
{
|
||||
comp_count++;
|
||||
if (nums[j] > nums[j + 1])
|
||||
{
|
||||
swap(nums[j], nums[j + 1]);
|
||||
move_count += 3; // std::swap is 3 moves
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
if (!swapped)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
sort_closet/code-sorting/DualPivotQuickSort.cpp
Normal file
67
sort_closet/code-sorting/DualPivotQuickSort.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void dualPivotQuickSortHelper(vector<int>& nums, int left, int right, long long& comp_count, long long& move_count) {
|
||||
if (left < right) {
|
||||
comp_count++;
|
||||
if (nums[left] > nums[right]) {
|
||||
swap(nums[left], nums[right]);
|
||||
move_count += 3;
|
||||
}
|
||||
|
||||
int p = nums[left], q = nums[right];
|
||||
int l = left + 1, g = right - 1, k = l;
|
||||
|
||||
while (k <= g) {
|
||||
comp_count++;
|
||||
if (nums[k] < p) {
|
||||
swap(nums[k], nums[l]);
|
||||
move_count += 3;
|
||||
l++;
|
||||
} else {
|
||||
comp_count++;
|
||||
if (nums[k] > q) {
|
||||
while (k < g && (comp_count++, nums[g] > q)) {
|
||||
g--;
|
||||
}
|
||||
swap(nums[k], nums[g]);
|
||||
move_count += 3;
|
||||
g--;
|
||||
comp_count++;
|
||||
if (nums[k] < p) {
|
||||
swap(nums[k], nums[l]);
|
||||
move_count += 3;
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
l--;
|
||||
g++;
|
||||
|
||||
swap(nums[left], nums[l]);
|
||||
move_count += 3;
|
||||
swap(nums[right], nums[g]);
|
||||
move_count += 3;
|
||||
|
||||
dualPivotQuickSortHelper(nums, left, l - 1, comp_count, move_count);
|
||||
dualPivotQuickSortHelper(nums, l + 1, g - 1, comp_count, move_count);
|
||||
dualPivotQuickSortHelper(nums, g + 1, right, comp_count, move_count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* function : implement dual pivot quick sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void DualPivotQuickSort(vector<int>& nums, long long& comp_count, long long& move_count) {
|
||||
if (nums.empty()) return;
|
||||
dualPivotQuickSortHelper(nums, 0, nums.size() - 1, comp_count, move_count);
|
||||
}
|
||||
33
sort_closet/code-sorting/InsertSort.cpp
Normal file
33
sort_closet/code-sorting/InsertSort.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
/*
|
||||
* function : implement insert sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void InsertSort(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
for (int i = 1; i < static_cast<int>(nums.size()); i++)
|
||||
{
|
||||
int key = nums[i];
|
||||
int j = i - 1;
|
||||
while (j >= 0 && (comp_count++, nums[j] > key))
|
||||
{
|
||||
nums[j + 1] = nums[j];
|
||||
move_count++;
|
||||
j--;
|
||||
}
|
||||
nums[j + 1] = key;
|
||||
move_count++;
|
||||
}
|
||||
}
|
||||
36
sort_closet/code-sorting/Makefile
Normal file
36
sort_closet/code-sorting/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
# Compiler and flags
|
||||
CXX := g++
|
||||
CXXFLAGS := -std=c++11 -Wall -O2
|
||||
|
||||
# Executable name
|
||||
TARGET := sorting_experiment
|
||||
|
||||
# Source files
|
||||
# Automatically find all .cpp files in the current directory
|
||||
SRCS := $(wildcard *.cpp)
|
||||
|
||||
# Object files
|
||||
# Replace .cpp extension with .o
|
||||
OBJS := $(SRCS:.cpp=.o)
|
||||
|
||||
# Default target
|
||||
all: $(TARGET)
|
||||
|
||||
# Link the program
|
||||
$(TARGET): $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)
|
||||
|
||||
# Compile source files into object files
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
# Target to run the experiment
|
||||
run: all
|
||||
@./$(TARGET)
|
||||
|
||||
# Clean up build files
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all clean run
|
||||
86
sort_closet/code-sorting/MergeSort.cpp
Normal file
86
sort_closet/code-sorting/MergeSort.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void merge(vector<int> &nums, int left, int mid, int right, long long &comp_count, long long &move_count)
|
||||
{
|
||||
int n1 = mid - left + 1;
|
||||
int n2 = right - mid;
|
||||
|
||||
vector<int> L(n1), R(n2);
|
||||
|
||||
for (int i = 0; i < n1; i++)
|
||||
{
|
||||
L[i] = nums[left + i];
|
||||
move_count++;
|
||||
}
|
||||
for (int j = 0; j < n2; j++)
|
||||
{
|
||||
R[j] = nums[mid + 1 + j];
|
||||
move_count++;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = left;
|
||||
|
||||
while (i < n1 && j < n2)
|
||||
{
|
||||
comp_count++;
|
||||
if (L[i] <= R[j])
|
||||
{
|
||||
nums[k] = L[i];
|
||||
move_count++;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
nums[k] = R[j];
|
||||
move_count++;
|
||||
j++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
while (i < n1)
|
||||
{
|
||||
nums[k] = L[i];
|
||||
move_count++;
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
|
||||
while (j < n2)
|
||||
{
|
||||
nums[k] = R[j];
|
||||
move_count++;
|
||||
j++;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
void mergeSortHelper(vector<int> &nums, int left, int right, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (left < right)
|
||||
{
|
||||
int mid = left + (right - left) / 2;
|
||||
mergeSortHelper(nums, left, mid, comp_count, move_count);
|
||||
mergeSortHelper(nums, mid + 1, right, comp_count, move_count);
|
||||
merge(nums, left, mid, right, comp_count, move_count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* function : implement merge sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void MergeSort(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (nums.empty()) return;
|
||||
mergeSortHelper(nums, 0, nums.size() - 1, comp_count, move_count);
|
||||
}
|
||||
48
sort_closet/code-sorting/QuickSort.cpp
Normal file
48
sort_closet/code-sorting/QuickSort.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int partition(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
int pivot = nums[high];
|
||||
int i = (low - 1);
|
||||
|
||||
for (int j = low; j <= high - 1; j++)
|
||||
{
|
||||
comp_count++;
|
||||
if (nums[j] < pivot)
|
||||
{
|
||||
i++;
|
||||
swap(nums[i], nums[j]);
|
||||
move_count += 3;
|
||||
}
|
||||
}
|
||||
swap(nums[i + 1], nums[high]);
|
||||
move_count += 3;
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
void quickSortHelper(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (low < high)
|
||||
{
|
||||
int pi = partition(nums, low, high, comp_count, move_count);
|
||||
quickSortHelper(nums, low, pi - 1, comp_count, move_count);
|
||||
quickSortHelper(nums, pi + 1, high, comp_count, move_count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* function : implement quick sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void QuickSort(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (nums.empty()) return;
|
||||
quickSortHelper(nums, 0, nums.size() - 1, comp_count, move_count);
|
||||
}
|
||||
70
sort_closet/code-sorting/QuickSort3Way.cpp
Normal file
70
sort_closet/code-sorting/QuickSort3Way.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* This function partitions the array into three parts:
|
||||
* a) arr[l..i] contains all elements smaller than pivot
|
||||
* b) arr[i+1..j-1] contains all elements equal to pivot
|
||||
* c) arr[j..r] contains all elements greater than pivot
|
||||
*/
|
||||
void partition3Way(vector<int> &nums, int l, int r, int &i, int &j, long long &comp_count, long long &move_count)
|
||||
{
|
||||
// To handle cases where array is sorted or nearly sorted
|
||||
int mid = l + (r - l) / 2;
|
||||
swap(nums[mid], nums[l]);
|
||||
move_count += 3;
|
||||
|
||||
i = l, j = r + 1;
|
||||
int pivot = nums[l];
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (comp_count++, nums[++i] < pivot)
|
||||
if (i == r) break;
|
||||
|
||||
while (comp_count++, pivot < nums[--j])
|
||||
if (j == l) break;
|
||||
|
||||
// check if pointers cross
|
||||
if (i >= j) break;
|
||||
|
||||
swap(nums[i], nums[j]);
|
||||
move_count += 3;
|
||||
}
|
||||
|
||||
swap(nums[l], nums[j]);
|
||||
move_count += 3;
|
||||
i = j; // Return the pivot position
|
||||
}
|
||||
|
||||
|
||||
void quickSort3WayHelper(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (high <= low) return;
|
||||
|
||||
int i, j;
|
||||
|
||||
partition3Way(nums, low, high, i, j, comp_count, move_count);
|
||||
|
||||
quickSort3WayHelper(nums, low, i - 1, comp_count, move_count);
|
||||
quickSort3WayHelper(nums, i + 1, high, comp_count, move_count);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* function : implement 3-way quick sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void QuickSort3Way(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (nums.empty()) return;
|
||||
// For better performance on random data, shuffle is recommended, but we'll skip for this experiment
|
||||
// random_shuffle(nums.begin(), nums.end());
|
||||
quickSort3WayHelper(nums, 0, nums.size() - 1, comp_count, move_count);
|
||||
}
|
||||
81
sort_closet/code-sorting/QuickSortOptimized.cpp
Normal file
81
sort_closet/code-sorting/QuickSortOptimized.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Helper to find median of three and swap pivot to the end
|
||||
int medianOfThree(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
int mid = low + (high - low) / 2;
|
||||
|
||||
comp_count++;
|
||||
if (nums[low] > nums[mid])
|
||||
{
|
||||
swap(nums[low], nums[mid]);
|
||||
move_count += 3;
|
||||
}
|
||||
comp_count++;
|
||||
if (nums[low] > nums[high])
|
||||
{
|
||||
swap(nums[low], nums[high]);
|
||||
move_count += 3;
|
||||
}
|
||||
comp_count++;
|
||||
if (nums[mid] > nums[high])
|
||||
{
|
||||
swap(nums[mid], nums[high]);
|
||||
move_count += 3;
|
||||
}
|
||||
|
||||
// Now nums[low] <= nums[mid] <= nums[high]
|
||||
// Pivot is nums[mid], but we swap it with nums[high-1] to use in partition
|
||||
// The partition logic will ignore the already sorted nums[low] and nums[high]
|
||||
swap(nums[mid], nums[high]); // Move pivot to the end
|
||||
move_count += 3;
|
||||
return nums[high];
|
||||
}
|
||||
|
||||
|
||||
int partition_optimized(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
int pivot = medianOfThree(nums, low, high, comp_count, move_count);
|
||||
int i = (low - 1);
|
||||
|
||||
for (int j = low; j <= high - 1; j++)
|
||||
{
|
||||
comp_count++;
|
||||
if (nums[j] < pivot)
|
||||
{
|
||||
i++;
|
||||
swap(nums[i], nums[j]);
|
||||
move_count += 3;
|
||||
}
|
||||
}
|
||||
swap(nums[i + 1], nums[high]);
|
||||
move_count += 3;
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
void quickSortOptimizedHelper(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (low < high)
|
||||
{
|
||||
int pi = partition_optimized(nums, low, high, comp_count, move_count);
|
||||
quickSortOptimizedHelper(nums, low, pi - 1, comp_count, move_count);
|
||||
quickSortOptimizedHelper(nums, pi + 1, high, comp_count, move_count);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* function : implement quick sort with median-of-three pivot selection
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void QuickSortOptimized(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
if (nums.empty()) return;
|
||||
quickSortOptimizedHelper(nums, 0, nums.size() - 1, comp_count, move_count);
|
||||
}
|
||||
82
sort_closet/code-sorting/README-zh.md
Normal file
82
sort_closet/code-sorting/README-zh.md
Normal file
@ -0,0 +1,82 @@
|
||||
# 排序算法性能分析项目
|
||||
|
||||
本项目使用 C++ 实现并深入分析了多种经典排序算法的性能。项目提供了一个自动化测试框架,能够在不同规模的随机生成数据集上对每种算法进行测试,并精确测量其**执行时间**、**比较次数**和**移动次数**,以供量化分析。
|
||||
|
||||
## 项目内容与实现方式
|
||||
|
||||
### 1. 模块化的算法实现
|
||||
为了保证代码的清晰度和可扩展性,每一种排序算法都作为独立的模块在各自的 `.cpp` 文件中实现。所有算法的函数声明都统一在 `algorithm.h` 头文件中进行管理。
|
||||
|
||||
这种结构使得添加新的算法或修改现有算法变得非常简单。
|
||||
|
||||
### 2. 精确的性能指标统计
|
||||
为了超越单纯的运行时间测量,本项目在每种排序算法的实现内部进行了“插桩”,以统计两个核心的性能指标:
|
||||
- **比较次数 (Comparisons)**:算法执行过程中元素之间进行比较的总次数。
|
||||
- **移动次数 (Moves)**:算法执行过程中数据的赋值、交换等移动操作的总次数。一个 `std::swap` 操作计为3次移动。
|
||||
|
||||
这些数据为理论复杂度分析提供了有力的实验验证。
|
||||
|
||||
### 3. 自动化的测试与分析框架
|
||||
项目核心是一个位于 `main.cpp` 的自动化测试框架,其主要功能包括:
|
||||
- **多算法支持**:能够自动运行所有已实现的排序算法。
|
||||
- **多规模测试**:支持在一系列预设的数据规模(例如 100, 1000, ..., 500,000)上进行测试。
|
||||
- **结果可靠性**:通过对每个规模进行多次重复实验并计算平均值,有效消除了单次运行的随机性误差。
|
||||
- **正确性校验**:在每次排序任务完成后,自动检查数组是否真正有序,确保了算法实现的正确性。
|
||||
- **格式化输出**:将所有测试结果以清晰的表格形式输出到控制台,方便用户阅读和分析。
|
||||
|
||||
## 已实现的排序算法
|
||||
|
||||
本项目共实现了以下算法:
|
||||
|
||||
#### 基础排序算法
|
||||
- **插入排序 (Insert Sort)**
|
||||
- **冒泡排序 (Bubble Sort)**
|
||||
- **希尔排序 (Shell Sort)**
|
||||
- **归并排序 (Merge Sort)**
|
||||
|
||||
#### 快速排序 (Quick Sort) 变体
|
||||
- **标准快速排序**:选择最后一个元素作为基准点。
|
||||
- **三数取中优化快速排序 (QuickSortOptimized)**:通过“三数取中”策略选择基准点,以提高算法在特殊数据(如部分有序)下的稳定性。
|
||||
- **三路快速排序 (QuickSort3Way)**:特别适用于处理含有大量重复元素的数组。
|
||||
- **双基准快速排序 (Dual-Pivot Quick Sort)**:使用两个基准点将数组划分为三部分,理论上能减少比较次数,在现代处理器上性能优异。
|
||||
|
||||
## 如何编译与运行
|
||||
|
||||
项目提供了一个 `Makefile` 文件,极大地简化了编译、运行和清理流程。
|
||||
|
||||
### 1. 编译项目
|
||||
在项目根目录下,执行以下命令来编译所有源代码:
|
||||
```bash
|
||||
make
|
||||
```
|
||||
该命令会自动调用 `g++` 编译器,并将所有 `.cpp` 文件编译链接成一个名为 `sorting_experiment` 的可执行文件。
|
||||
|
||||
### 2. 运行实验
|
||||
编译成功后,执行以下命令来运行完整的性能分析测试:
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
你也可以直接运行生成的可执行文件:
|
||||
```bash
|
||||
./sorting_experiment
|
||||
```
|
||||
程序启动后,将开始对所有算法和所有预设规模进行测试,并将结果实时输出到控制台。
|
||||
|
||||
### 3. 清理生成文件
|
||||
如果你想删除所有编译生成的目标文件 (`.o`) 和可执行文件,可以运行:
|
||||
```bash
|
||||
make clean
|
||||
```
|
||||
|
||||
## 输出结果解读
|
||||
|
||||
程序的输出是一个性能指标表格,每一行代表一种算法在一个特定数据规模下的平均测试结果。
|
||||
|
||||
| 列名 | 中文说明 |
|
||||
| :--- | :--- |
|
||||
| **Algorithm** | 被测试的排序算法的名称。 |
|
||||
| **Size** | 当前测试的数组大小(即数据规模 `n`)。 |
|
||||
| **Avg Time (s)** | 多次重复测试下的平均运行时间,单位为秒。 |
|
||||
| **Avg Comparisons**| 平均比较操作的次数。 |
|
||||
| **Avg Moves** | 平均移动(赋值或交换)操作的次数。 |
|
||||
| **Correct?** | 排序结果是否正确,"Yes" 代表正确无误。 |
|
||||
77
sort_closet/code-sorting/README.md
Normal file
77
sort_closet/code-sorting/README.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Sorting Algorithm Performance Analysis
|
||||
|
||||
This project implements and analyzes the performance of several classic sorting algorithms in C++. It provides a framework to test each algorithm on randomly generated data of various sizes, measuring execution time, comparison counts, and move counts.
|
||||
|
||||
A detailed analysis and discussion of the results can be found in [REPORT.md](./REPORT.md).
|
||||
|
||||
## Implemented Algorithms
|
||||
|
||||
- **Basic Sorting Algorithms:**
|
||||
- Insertion Sort
|
||||
- Bubble Sort
|
||||
- Shell Sort
|
||||
- Merge Sort
|
||||
|
||||
- **Quick Sort Variants:**
|
||||
- Standard Quick Sort (pivot is the last element)
|
||||
- Quick Sort with Median-of-Three pivot optimization
|
||||
- 3-Way Quick Sort (for handling duplicate keys)
|
||||
- Dual-Pivot Quick Sort
|
||||
|
||||
## How to Build and Run
|
||||
|
||||
A `Makefile` is provided to simplify the build and execution process.
|
||||
|
||||
### 1. Build the Project
|
||||
|
||||
To compile all the source files and create the executable, run:
|
||||
```bash
|
||||
make
|
||||
```
|
||||
This will generate an executable file named `sorting_experiment`.
|
||||
|
||||
### 2. Run the Experiment
|
||||
|
||||
To run the performance analysis, execute the following command:
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
Alternatively, you can run the executable directly:
|
||||
```bash
|
||||
./sorting_experiment
|
||||
```
|
||||
The program will output a formatted table with the performance metrics for each algorithm across different data sizes.
|
||||
|
||||
### 3. Clean Up
|
||||
|
||||
To remove the compiled object files and the executable, run:
|
||||
```bash
|
||||
make clean
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary><strong>Original Experiment Requirements</strong></summary>
|
||||
|
||||
### 实验内容
|
||||
对几种经典的排序算法进行分析,理解算法在不同输入时的表现,深入剖析算法优缺点及其根源。具体要求如下:
|
||||
|
||||
1. 实现常见排序算法,至少要实现插入排序、冒泡排序、快速排序、归并排序、shell排序算法;
|
||||
2. 在排序算法中插桩,记录关键操作次数(如比较次数、移动次数等);
|
||||
3. 以待排序文件的行数n为输入规模,固定n随机产生多组测试样本,统计算法的平均运行时间和关键操作次数,改变n的规模重复多次实验,并对结果进行统计;
|
||||
4. 改变数组规模,对不同规模问题下各算法的结果进行统计并绘制图表,与理论值进行对照分析;
|
||||
5. 优化快速排序的中枢点选取,对优化前后的性能进行分析;
|
||||
6. 对快速排序的三种实现进行性能比较。
|
||||
|
||||
### 附加:
|
||||
|
||||
- 实现BlockQuickSort,就分支预测次数展开分析;
|
||||
- 实现DualPivotQuickSort,就递归深度展开分析;
|
||||
- 在超大规模数据上(如1亿个整数),对比以上快排实现的性能。
|
||||
|
||||
### 编写实验文档:
|
||||
|
||||
要求对所实现算法的时间进行复杂度分析(结合程序统计关键步骤运行次数,以验证分析结果);程序运行指导,包括程序编译说明、输入输出示例等。如果输入、输出信息较多,建议采用文件进行格式化输入、输出。实验报告:解题思路;所实现算法的时间复杂度分析(结合程序统计关键步骤运行次数,以验证分析结果);程序运行指导,包括程序编译说明、输入输出示例等。如果输入、输出信息较多,建议采用文件进行格式化输入、输出。
|
||||
|
||||
</details>
|
||||
98
sort_closet/code-sorting/REPORT.md
Normal file
98
sort_closet/code-sorting/REPORT.md
Normal file
@ -0,0 +1,98 @@
|
||||
# 排序算法实验报告
|
||||
|
||||
## 1. 解题思路
|
||||
|
||||
本实验旨在深入理解并分析多种经典排序算法的性能。为了达成此目标,实验遵循了以下设计思路:
|
||||
|
||||
1. **模块化实现**:将每种排序算法(插入、冒泡、希尔、归并、快速排序及其变体)分别实现在独立的 `.cpp` 文件中,并通过一个统一的 `algorithm.h` 头文件进行声明。这种结构使得代码清晰、易于扩展和维护。
|
||||
|
||||
2. **量化性能指标**:为了客观评估算法性能,除了记录运行时间外,还在算法实现中进行“插桩”,精确统计了两个关键操作:
|
||||
* **比较次数 (Comparisons)**:元素之间的比较操作,是决定算法时间复杂度的核心因素之一。
|
||||
* **移动次数 (Moves)**:元素的赋值或交换操作,反映了算法的数据搬运成本。
|
||||
|
||||
3. **自动化测试框架**:设计了一个灵活的测试框架 (`main.cpp`),能够:
|
||||
* 自动化地对所有已实现的算法进行测试。
|
||||
* 支持对多种不同的输入规模(例如 100, 1000, ..., 500,000)进行测试。
|
||||
* 通过多次重复实验并取平均值的方式,消除单次运行的随机误差,保证结果的可靠性。
|
||||
* 在每次排序后进行正确性校验,确保算法实现无误。
|
||||
* 以格式化的表格输出结果,便于阅读和后续分析。
|
||||
|
||||
4. **迭代优化与对比**:重点对快速排序进行了深度探索,实现了从基础版本到优化版本(三数取中、三路快排、双基准快排)的演进。通过将这些版本置于同一测试框架下进行性能对比,可以直观地展示不同优化策略带来的效果。
|
||||
|
||||
## 2. 算法复杂度分析与实验数据验证
|
||||
|
||||
### 理论分析
|
||||
|
||||
| 算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **InsertSort** | O(n²) | O(n) | O(n²) | O(1) |
|
||||
| **BubbleSort** | O(n²) | O(n) | O(n²) | O(1) |
|
||||
| **ShellSort** | O(n log n) ~ O(n²) | O(n log n) | O(n²) | O(1) |
|
||||
| **MergeSort** | O(n log n) | O(n log n) | O(n log n) | O(n) |
|
||||
| **QuickSort** | O(n log n) | O(n log n) | O(n²) | O(log n) |
|
||||
| **QuickSortOpt** | O(n log n) | O(n log n) | O(n²) | O(log n) |
|
||||
| **QuickSort3Way**| O(n log n) | O(n) | O(n²) | O(log n) |
|
||||
| **DualPivotSort**| O(n log n) | O(n log n) | O(n²) | O(log n) |
|
||||
|
||||
### 实验数据验证
|
||||
|
||||
通过运行实验程序,可以得到不同算法在不同规模下的平均运行时间、比较次数和移动次数。这些数据可以用来验证上述理论复杂度。
|
||||
|
||||
* **O(n²) 算法 (InsertSort, BubbleSort)**:
|
||||
* **预期**:当输入规模 `n` 增大10倍时,运行时间、比较和移动次数大约会增大100倍。
|
||||
* **观察**:从实验数据中可以看到,当 `n` 从 1000 增加到 10000 时,`InsertSort` 和 `BubbleSort` 的运行时间急剧增加,远超线性增长,这与 O(n²) 的特征相符。由于性能问题,测试框架在 `n >= 50000` 时自动跳过了这些算法。
|
||||
|
||||
* **O(n log n) 算法 (MergeSort, QuickSort 变体)**:
|
||||
* **预期**:当输入规模 `n` 增大时,性能增长平缓。比较次数大致在 `n * log(n)` 的量级。
|
||||
* **观察**:`MergeSort` 和各种 `QuickSort` 的运行时间随 `n` 的增长远比 O(n²) 算法要慢。例如,从 `n=10000` 到 `n=100000`(10倍),它们的运行时间增长远小于100倍,符合 `n log n` 的趋势。`MergeSort` 的比较次数非常稳定,接近理论值。
|
||||
|
||||
* **快速排序变体对比**:
|
||||
* `QuickSort` (基础版) 在随机数据下表现良好,但如果输入数据有序,其性能会退化到 O(n²)。
|
||||
* `QuickSortOpt` (三数取中) 通过改进基准点选择,显著提高了在非完全随机数据下的稳定性,其比较和移动次数通常略优于基础版。
|
||||
* `QuickSort3Way` 在处理含大量重复元素的数组时优势最大(本次实验为随机数据,优势不明显),其在最好情况下(所有元素相同)可达 O(n)。
|
||||
* `DualPivotSort` (双基准) 在理论上可以减少比较次数。从实验数据看,在较大规模的数据集上(如 `n=100000` 及以上),它通常比单基准的快速排序更快,显示出其优化效果。
|
||||
|
||||
## 3. 程序运行指导
|
||||
|
||||
### 编译
|
||||
|
||||
所有相关的 `.cpp` 源文件需要一起编译。可以使用 g++ 编译器,命令如下:
|
||||
|
||||
```bash
|
||||
g++ main.cpp InsertSort.cpp BubbleSort.cpp ShellSort.cpp MergeSort.cpp QuickSort.cpp QuickSortOptimized.cpp QuickSort3Way.cpp DualPivotQuickSort.cpp out.cpp -o sorting_experiment
|
||||
```
|
||||
|
||||
此命令会生成一个名为 `sorting_experiment` 的可执行文件。
|
||||
|
||||
### 运行
|
||||
|
||||
直接在终端中运行生成的可执行文件:
|
||||
|
||||
```bash
|
||||
./sorting_experiment
|
||||
```
|
||||
|
||||
### 输出结果说明
|
||||
|
||||
程序会输出一个性能分析表格,每一行代表一个算法在一个特定输入规模下的测试结果。
|
||||
|
||||
| 列 | 说明 |
|
||||
| :--- | :--- |
|
||||
| **Algorithm** | 被测试的排序算法名称。 |
|
||||
| **Size** | 输入数组的元素个数(即规模 `n`)。 |
|
||||
| **Avg Time (s)** | 多次重复测试的平均运行时间,单位为秒。 |
|
||||
| **Avg Comparisons**| 平均比较次数。 |
|
||||
| **Avg Moves** | 平均移动(赋值/交换)次数。 |
|
||||
| **Correct?** | 排序结果是否正确,"Yes" 表示正确。 |
|
||||
|
||||
## 4. 性能对比与结论
|
||||
|
||||
1. **算法类别差异**:O(n²) 级别的算法(插入排序、冒泡排序)仅适用于小规模数据。当数据规模超过一万时,其性能急剧下降,无法在实际应用中使用。相比之下,O(n log n) 级别的算法(归并、希尔、快速排序)则表现出卓越的性能和可扩展性。
|
||||
|
||||
2. **快速排序的优势与优化**:在所有 O(n log n) 算法中,快速排序及其变体通常在平均情况下的性能最好,这得益于其更少的常量因子和高效的缓存利用率。
|
||||
* **基准点选择至关重要**:基础的快速排序在特定数据模式下存在性能退化的风险,而“三数取中”等优化策略能有效缓解此问题,增强算法的稳定性。
|
||||
* **双基准快排的威力**:`DualPivotQuickSort` 在大规模随机数据上展现了最佳性能,验证了其在现代计算环境下的理论优势。
|
||||
|
||||
3. **归并排序的稳定性**:虽然 `MergeSort` 在本次测试中的原始速度略逊于最优的快速排序,但它具有一个重要优点:其性能是稳定的 O(n log n),不受输入数据初始顺序的影响。此外,归并排序是一种稳定的排序算法,而快速排序不是。
|
||||
|
||||
**最终结论**:对于通用场景下的内部排序任务,经过优化的快速排序(特别是双基准快速排序)是性能上的首选。而当需要排序稳定性或对最坏情况有严格要求时,归并排序是更可靠的选择。
|
||||
32
sort_closet/code-sorting/ShellSort.cpp
Normal file
32
sort_closet/code-sorting/ShellSort.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* function : implement shell sort
|
||||
* param nums : the vector to be sorted
|
||||
* param comp_count : count of comparisons
|
||||
* param move_count : count of moves
|
||||
* return : ---
|
||||
*/
|
||||
void ShellSort(vector<int> &nums, long long &comp_count, long long &move_count)
|
||||
{
|
||||
int n = nums.size();
|
||||
for (int gap = n / 2; gap > 0; gap /= 2)
|
||||
{
|
||||
for (int i = gap; i < n; i += 1)
|
||||
{
|
||||
int temp = nums[i];
|
||||
int j;
|
||||
for (j = i; j >= gap && (comp_count++, nums[j - gap] > temp); j -= gap)
|
||||
{
|
||||
nums[j] = nums[j - gap];
|
||||
move_count++;
|
||||
}
|
||||
nums[j] = temp;
|
||||
move_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
sort_closet/code-sorting/algorithm.h
Normal file
20
sort_closet/code-sorting/algorithm.h
Normal file
@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void InsertSort(vector<int>&, long long&, long long&);
|
||||
void BubbleSort(vector<int>&, long long&, long long&);
|
||||
void MergeSort(vector<int>&, long long&, long long&);
|
||||
void QuickSort(vector<int>&, long long&, long long&);
|
||||
void QuickSortOptimized(vector<int>&, long long&, long long&);
|
||||
void QuickSort3Way(vector<int>&, long long&, long long&);
|
||||
void DualPivotQuickSort(vector<int>&, long long&, long long&);
|
||||
void ShellSort(vector<int>&, long long&, long long&);
|
||||
|
||||
BIN
sort_closet/code-sorting/average_comparisons_vs_size.png
Normal file
BIN
sort_closet/code-sorting/average_comparisons_vs_size.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
BIN
sort_closet/code-sorting/average_moves_vs_size.png
Normal file
BIN
sort_closet/code-sorting/average_moves_vs_size.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
BIN
sort_closet/code-sorting/average_time_vs_size.png
Normal file
BIN
sort_closet/code-sorting/average_time_vs_size.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
110
sort_closet/code-sorting/main.cpp
Normal file
110
sort_closet/code-sorting/main.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include "algorithm.h"
|
||||
#include "out.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define UP_BOUND 1000000
|
||||
|
||||
// Function pointer for sorting algorithms
|
||||
typedef void (*SortFunction)(vector<int>&, long long&, long long&);
|
||||
|
||||
bool is_sorted(const vector<int>& vec)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size() - 1; ++i)
|
||||
{
|
||||
if (vec[i] > vec[i + 1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void run_performance_analysis()
|
||||
{
|
||||
cout << "--- Running Performance Analysis ---" << endl;
|
||||
|
||||
SortFunction algorithms[] = {InsertSort, BubbleSort, ShellSort, MergeSort, QuickSort, QuickSortOptimized, QuickSort3Way, DualPivotQuickSort};
|
||||
string algo_names[] = {"InsertSort", "BubbleSort", "ShellSort", "MergeSort", "QuickSort", "QuickSortOpt", "QuickSort3Way", "DualPivotSort"};
|
||||
int num_algorithms = sizeof(algorithms) / sizeof(algorithms[0]);
|
||||
|
||||
vector<int> sizes = {100, 1000, 10000, 50000, 100000, 500000};
|
||||
int num_repeats = 10;
|
||||
|
||||
cout << left << setw(15) << "Algorithm"
|
||||
<< setw(10) << "Size"
|
||||
<< setw(20) << "Avg Time (s)"
|
||||
<< setw(25) << "Avg Comparisons"
|
||||
<< setw(25) << "Avg Moves"
|
||||
<< setw(15) << "Correct?" << endl;
|
||||
cout << string(110, '-') << endl;
|
||||
|
||||
for (int i = 0; i < num_algorithms; i++)
|
||||
{
|
||||
for (int size : sizes)
|
||||
{
|
||||
if (size >= 50000 && (algo_names[i] == "InsertSort" || algo_names[i] == "BubbleSort"))
|
||||
{
|
||||
cout << left << setw(15) << algo_names[i]
|
||||
<< setw(10) << size << " -> Skipped" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
double total_time = 0;
|
||||
long long total_comps = 0;
|
||||
long long total_moves = 0;
|
||||
bool all_correct = true;
|
||||
|
||||
for (int j = 0; j < num_repeats; j++)
|
||||
{
|
||||
vector<int> vec(size);
|
||||
for (int k = 0; k < size; k++)
|
||||
vec[k] = rand() % UP_BOUND;
|
||||
|
||||
long long comp_count = 0;
|
||||
long long move_count = 0;
|
||||
|
||||
vector<int> temp_vec = vec;
|
||||
|
||||
clock_t start_time = clock();
|
||||
algorithms[i](temp_vec, comp_count, move_count);
|
||||
clock_t end_time = clock();
|
||||
|
||||
if (!is_sorted(temp_vec))
|
||||
{
|
||||
all_correct = false;
|
||||
}
|
||||
|
||||
total_time += (double)(end_time - start_time) / CLOCKS_PER_SEC;
|
||||
total_comps += comp_count;
|
||||
total_moves += move_count;
|
||||
}
|
||||
|
||||
cout << left << setw(15) << algo_names[i]
|
||||
<< setw(10) << size
|
||||
<< fixed << setprecision(6) << setw(20) << total_time / num_repeats
|
||||
<< setw(25) << total_comps / num_repeats
|
||||
<< setw(25) << total_moves / num_repeats
|
||||
<< setw(15) << (all_correct ? "Yes" : "No") << endl;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
cout << "------------------------------------" << endl;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
srand(time(0)); // Seed for random number generation
|
||||
|
||||
run_performance_analysis();
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
sort_closet/code-sorting/out.cpp
Normal file
16
sort_closet/code-sorting/out.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* function : print a vector
|
||||
* param nums : the vector to be printed
|
||||
* return : ---
|
||||
*/
|
||||
void Out(vector<int> &nums)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(nums.size()); i++)
|
||||
cout << nums[i] << " ";
|
||||
cout << endl;
|
||||
}
|
||||
6
sort_closet/code-sorting/out.h
Normal file
6
sort_closet/code-sorting/out.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Out(vector<int> &);
|
||||
138
sort_closet/code-sorting/plot_results.py
Normal file
138
sort_closet/code-sorting/plot_results.py
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import io
|
||||
|
||||
output = """
|
||||
--- Running Performance Analysis ---
|
||||
Algorithm Size Avg Time (s) Avg Comparisons Avg Moves Correct?
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
InsertSort 100 0.000006 2628 2633 Yes
|
||||
InsertSort 1000 0.000108 251895 251902 Yes
|
||||
InsertSort 10000 0.010841 25002574 25002583 Yes
|
||||
InsertSort 50000 -> Skipped
|
||||
InsertSort 100000 -> Skipped
|
||||
InsertSort 500000 -> Skipped
|
||||
|
||||
BubbleSort 100 0.000018 4891 7118 Yes
|
||||
BubbleSort 1000 0.001527 498086 754888 Yes
|
||||
BubbleSort 10000 0.147654 49984024 74752463 Yes
|
||||
BubbleSort 50000 -> Skipped
|
||||
BubbleSort 100000 -> Skipped
|
||||
BubbleSort 500000 -> Skipped
|
||||
|
||||
ShellSort 100 0.000003 859 911 Yes
|
||||
ShellSort 1000 0.000040 15404 15912 Yes
|
||||
ShellSort 10000 0.000577 263303 268383 Yes
|
||||
ShellSort 50000 0.003500 1883075 1908568 Yes
|
||||
ShellSort 100000 0.007738 4329053 4379481 Yes
|
||||
ShellSort 500000 0.047314 28756169 29008608 Yes
|
||||
|
||||
MergeSort 100 0.000005 541 1344 Yes
|
||||
MergeSort 1000 0.000053 8710 19952 Yes
|
||||
MergeSort 10000 0.000639 120467 267232 Yes
|
||||
MergeSort 50000 0.003562 718133 1568928 Yes
|
||||
MergeSort 100000 0.007466 1536366 3337856 Yes
|
||||
MergeSort 500000 0.042618 8837077 18951424 Yes
|
||||
|
||||
QuickSort 100 0.000002 633 1146 Yes
|
||||
QuickSort 1000 0.000027 11070 18485 Yes
|
||||
QuickSort 10000 0.000340 156205 257969 Yes
|
||||
QuickSort 50000 0.001971 938346 1488604 Yes
|
||||
QuickSort 100000 0.004147 2013584 3293229 Yes
|
||||
QuickSort 500000 0.023807 11835910 18761405 Yes
|
||||
|
||||
QuickSortOpt 100 0.000002 723 1306 Yes
|
||||
QuickSortOpt 1000 0.000029 10853 19089 Yes
|
||||
QuickSortOpt 10000 0.000359 152089 263599 Yes
|
||||
QuickSortOpt 50000 0.002079 889846 1472662 Yes
|
||||
QuickSortOpt 100000 0.004246 1894396 3081447 Yes
|
||||
QuickSortOpt 500000 0.025016 10915240 17611893 Yes
|
||||
|
||||
QuickSort3Way 100 0.000003 756 693 Yes
|
||||
QuickSort3Way 1000 0.000039 12003 9189 Yes
|
||||
QuickSort3Way 10000 0.000479 168509 114458 Yes
|
||||
QuickSort3Way 50000 0.002715 1013555 652409 Yes
|
||||
QuickSort3Way 100000 0.005945 2123298 1376911 Yes
|
||||
QuickSort3Way 500000 0.032901 12324462 7696985 Yes
|
||||
|
||||
DualPivotSort 100 0.000002 624 884 Yes
|
||||
DualPivotSort 1000 0.000026 10635 12297 Yes
|
||||
DualPivotSort 10000 0.000331 151783 170443 Yes
|
||||
DualPivotSort 50000 0.001911 908308 974849 Yes
|
||||
DualPivotSort 100000 0.004047 1926590 2053087 Yes
|
||||
DualPivotSort 500000 0.022747 11189537 11712207 Yes
|
||||
"""
|
||||
|
||||
# Use StringIO to treat the string data as a file
|
||||
data = io.StringIO(output)
|
||||
|
||||
# Read the data, skipping the header and footer
|
||||
df = pd.read_csv(data, sep='\s+', skiprows=3, skipfooter=1, engine='python',
|
||||
names=['Algorithm', 'Size', 'Avg Time (s)', 'Avg Comparisons', 'Avg Moves', 'Correct?'])
|
||||
|
||||
# Drop the 'Correct?' column as it's not needed for plotting
|
||||
df = df.drop(columns=['Correct?'])
|
||||
|
||||
# Remove rows with 'Skipped' values
|
||||
df = df[~df.isin(['->', 'Skipped']).any(axis=1)]
|
||||
|
||||
# Convert columns to numeric types
|
||||
for col in ['Size', 'Avg Time (s)', 'Avg Comparisons', 'Avg Moves']:
|
||||
df[col] = pd.to_numeric(df[col])
|
||||
|
||||
# Get the list of algorithms
|
||||
algorithms = df['Algorithm'].unique()
|
||||
|
||||
# Plotting
|
||||
plt.style.use('ggplot')
|
||||
|
||||
# --- Plot 1: Average Time vs. Size ---
|
||||
plt.figure(figsize=(12, 8))
|
||||
for algo in algorithms:
|
||||
subset = df[df['Algorithm'] == algo]
|
||||
plt.plot(subset['Size'], subset['Avg Time (s)'], marker='o', linestyle='-', label=algo)
|
||||
|
||||
plt.title('Average Time vs. Input Size')
|
||||
plt.xlabel('Input Size (n)')
|
||||
plt.ylabel('Average Time (seconds)')
|
||||
plt.xscale('log')
|
||||
plt.yscale('log')
|
||||
plt.legend()
|
||||
plt.grid(True, which="both", ls="--")
|
||||
plt.savefig('average_time_vs_size.png')
|
||||
plt.close()
|
||||
|
||||
# --- Plot 2: Average Comparisons vs. Size ---
|
||||
plt.figure(figsize=(12, 8))
|
||||
for algo in algorithms:
|
||||
subset = df[df['Algorithm'] == algo]
|
||||
plt.plot(subset['Size'], subset['Avg Comparisons'], marker='o', linestyle='-', label=algo)
|
||||
|
||||
plt.title('Average Comparisons vs. Input Size')
|
||||
plt.xlabel('Input Size (n)')
|
||||
plt.ylabel('Average Comparisons')
|
||||
plt.xscale('log')
|
||||
plt.yscale('log')
|
||||
plt.legend()
|
||||
plt.grid(True, which="both", ls="--")
|
||||
plt.savefig('average_comparisons_vs_size.png')
|
||||
plt.close()
|
||||
|
||||
# --- Plot 3: Average Moves vs. Size ---
|
||||
plt.figure(figsize=(12, 8))
|
||||
for algo in algorithms:
|
||||
subset = df[df['Algorithm'] == algo]
|
||||
plt.plot(subset['Size'], subset['Avg Moves'], marker='o', linestyle='-', label=algo)
|
||||
|
||||
plt.title('Average Moves vs. Input Size')
|
||||
plt.xlabel('Input Size (n)')
|
||||
plt.ylabel('Average Moves')
|
||||
plt.xscale('log')
|
||||
plt.yscale('log')
|
||||
plt.legend()
|
||||
plt.grid(True, which="both", ls="--")
|
||||
plt.savefig('average_moves_vs_size.png')
|
||||
plt.close()
|
||||
|
||||
print("Plots saved as average_time_vs_size.png, average_comparisons_vs_size.png, and average_moves_vs_size.png")
|
||||
BIN
sort_closet/code-sorting/实验一-C.zip
Normal file
BIN
sort_closet/code-sorting/实验一-C.zip
Normal file
Binary file not shown.
BIN
sort_closet/code-sorting/实验一-c.docx
Normal file
BIN
sort_closet/code-sorting/实验一-c.docx
Normal file
Binary file not shown.
Reference in New Issue
Block a user