Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

## 规范文件

规范文件位于 specs/ 目录中,其内的每个文件内包含必须遵守的开发规范。如果你发现各个规范文件之间有冲突,必须告诉用户。如果有对行为契约的变更,务必更新规范文件。
规范文件位于 specs/ 目录中,包含必须遵守的开发规范和功能行为契约。

如果你发现各个规范文件之间有冲突,必须告诉用户。如果有对功能行为契约的变更,务必更新规范文件,并提示用户。

## 计划文件

Expand All @@ -24,6 +26,11 @@
当用户要求你把制定好的开发计划写入到文件时,除非用户明确要求你写入到已有的计划文件,否则你必须写入到新计划文件。
除非用户要求,否则忽略计划文件目录内的计划文件(除了用户提到的文件),将它们视为历史计划。制定新计划时,不必变更旧的计划。

## README 文件和 wiki 目录

1. `README.md` 写项目介绍,快速开始指导和文档索引。
2. `wiki/` 写快速开始和算法使用教程。

## 功能实现注意事项

当用户要求你把某个计划文件落地实现:
Expand Down
47 changes: 9 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,21 @@
# StrangeSort

`StrangeSort` 是一个基于 .NET 10 的 C# 类库,只收录和实现几种冠以**经典人物的名字**的奇异算法。

这个仓库当前包含 5 组公开算法:

- `StalinSort`:从左到右删除违序元素,保留一个有序子序列。大力清洗所有不符合要求的元素!
- `ThanosSort`:随机删除当前序列的一半元素,重复执行直到序列有序。一键清除多余元素,剩下多少你别问,嘿嘿。
- `EpsteinSort`:先保留数值区间 `[0, 18)` 内的元素,再对保留元素排序。只保留未成年数字,太老的全部斩杀!
- `BrezhnevSort`:无视输入值本身,只根据输入长度把结果改写为从 `1` 到 `n` 的序数序列。内容不重要,排场最重要!
- `TrumpSort`:对输入内容执行一次随机重排。具体发生了什么不重要,先赢再说!
`StrangeSort` 是一个基于 `.NET 10` 的 C# 类库,实现几种冠以**历史经典人物**的名字的奇异算法。只是为了好玩!

## 快速开始

### 从 GitHub Packages 安装

当前包名是 `StrangeSort`,GitHub Packages 源地址示例为 `https://nuget.pkg.github.com/yhcedpn/index.json`。

首次使用时,先添加包源:

```powershell
dotnet nuget add source "https://nuget.pkg.github.com/yhcedpn/index.json" --name github-yhcedpn --username YOUR_GITHUB_USERNAME --password YOUR_GITHUB_PAT --store-password-in-clear-text
```

然后安装包:

```powershell
dotnet add package StrangeSort --version <VERSION> --source github-yhcedpn
```
NuGet 包名:`StrangeSort`

### 快速使用
GitHub Packages 源:`https://nuget.pkg.github.com/yhcedpn/index.json`

调用前通常需要引入对应命名空间:
[Wiki 快速开始](./wiki/Quick-Start.md):安装后的最小使用路径。

```csharp
using StrangeSort.StalinSort;
using StrangeSort.ThanosSort;
using StrangeSort.EpsteinSort;
using StrangeSort.BrezhnevSort;
using StrangeSort.TrumpSort;
## 文档索引

int[] source = [3, 1, 2, 4];
int[] result = StalinSorter.RemoveOutOfOrder(source);
```
1. [StrangeSort 开发规范](./specs/StrangeSort%20%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md):架构设计要求、变更防漂移规定、各算法行为协议。

## 详细文档
2. [StrangeSortTest 测试规范](./specs/StrangeSortTest%20%E6%B5%8B%E8%AF%95%E8%A7%84%E8%8C%83.md):边缘条件测试指南与测试约束。

详见 Wiki:<https://github.com/yhcedpn/StrangeSort/wiki>
3. [Wiki 主索引](./wiki/Home.md):文档入口。

公开行为契约以规范文件为准,`README.md` 与 GitHub Wiki 只承担项目介绍、导航和补充说明职责:[StrangeSort 项目开发规范](https://github.com/yhcedpn/StrangeSort/blob/main/specs/StrangeSort%20%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md)
4. `wiki/*-Guide.md`:各算法使用教程页。
89 changes: 89 additions & 0 deletions specs/StrangeSort 开发规范.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# StrangeSort 开发规范

## 架构设计要求

1. 保持高内聚、低耦合。
2. 一个类型只负责一类明确职责,避免功能堆叠。
3. 优先组合而不是继承。
4. 公共 API 变更必须谨慎,未经明确要求不要新增、删除、重命名或重排公开重载。
5. 默认参数语义、泛型约束、枚举合法值和异常行为未经明确要求不得改变。
6. 实现可以重构,公开行为不能漂移。

## 变更防漂移规定

1. 修改算法前,先明确这次改动属于“修复实现偏离现有协议”还是“有意修改协议”。
2. 如果只是修复实现,必须保持本文件中的公开行为协议不变,并补测试证明协议仍成立。
3. 如果有意修改协议,必须在同一次改动中同步更新本文件、测试和受影响的 `README.md` 或 `wiki/`。
4. 禁止只改实现不改规范,也禁止只改测试去迎合实现。
5. 禁止把这些奇异算法静默改造成正常排序算法。
6. 禁止在没有公开说明的情况下改变空输入、单元素、重复值、随机源为空、比较器为空、非法枚举值、不可比较类型和溢出等边界行为。

## 算法行为协议

### StalinSort

公开 API 族:提供 `T[]` 和 `List<T>` 两组 `RemoveOutOfOrder` 重载,支持默认比较器和显式 `IComparer<T>`。

1. 从左到右扫描输入,第一个元素总是保留。
2. 仅当 `comparer.Compare(lastKept, current) <= 0` 时保留当前元素,否则删除。
3. 输出始终是输入的子序列,保留元素相对顺序不变;禁止交换、重排或额外排序。
4. 数组重载不修改输入数组。`values.Length <= 1` 时返回原数组引用;长度大于 `1` 时总返回新数组,即使输入本身已满足顺序。
5. `List<T>` 重载原地删除违序元素。
6. `comparer == null` 时使用 `Comparer<T>.Default`;只有真的发生比较时才要求 `T` 可比较。
7. `values == null` 时抛 `ArgumentNullException`;默认比较器不可用且运行时需要比较时抛 `ArgumentException`;自定义比较器异常原样传播。
8. 数组重载异常后输入保持不变;`List<T>` 重载异常后可能已部分修改,且不回滚。

### ThanosSort

公开 API 族:提供 `T[]` 和 `List<T>` 两组 `PruneUntilSorted` 重载,支持默认比较器、显式 `IComparer<T>`、`RemovalCountStrategy` 和 `Random`。

1. 反复检查当前序列是否有序;如果无序,就随机删除当前序列的一半元素;重复直到结果有序。
2. 输出始终是输入的有序子序列,且幸存元素保持原有相对顺序。
3. `RemovalCountStrategy.FloorHalf` 在奇数长度时删除 `count / 2`;`RemovalCountStrategy.CeilingHalf` 在奇数长度时删除 `(count + 1) / 2`。
4. 数组重载不修改输入数组。`values.Length <= 1` 或输入本身已排序时返回原数组引用;其余情况下返回新数组。
5. `List<T>` 重载原地随机删除元素,直到列表有序。
6. `comparer == null` 时使用 `Comparer<T>.Default`;`random == null` 时使用 `Random.Shared`;默认删除策略为 `FloorHalf`。
7. 使用相同输入、比较器、删除策略和显式随机种子时,数组重载可复现,列表重载可复现,且两者结果内容一致。
8. `values == null` 或显式传入的 `random == null` 时抛 `ArgumentNullException`;非法 `removalStrategy` 抛 `ArgumentOutOfRangeException`;默认比较器不可用且运行时需要比较时抛 `ArgumentException`;比较器和随机源异常原样传播。
9. 数组重载异常后输入保持不变;`List<T>` 重载异常后可能已部分修改,且不回滚。

### EpsteinSort

公开 API 族:提供 `T[]` 和 `List<T>` 两组 `RetainOnlyMinorsAndSort` 重载,支持默认比较器和显式 `IComparer<T>`,其中 `T : INumber<T>`。

1. 算法分两步:先过滤,再排序。
2. 过滤规则固定为只保留 `[0, 18)` 内的值。
3. 对浮点类型,`NaN`、`-Infinity` 和 `+Infinity` 都会被删除。
4. 过滤阶段不受比较器影响;比较器只参与最终排序。
5. 数组重载不修改输入数组,并始终返回结果数组,不返回原数组引用。
6. `List<T>` 重载先原地删除所有不在 `[0, 18)` 内的元素,再对保留元素排序。
7. `comparer == null` 时使用 `Comparer<T>.Default`。
8. `values == null` 时抛 `ArgumentNullException`。如果比较器在排序阶段抛出异常,底层排序 API 会抛 `InvalidOperationException`,原始比较器异常通常作为 `InnerException` 暴露。
9. 数组重载异常后输入保持不变;`List<T>` 重载排序失败时,过滤阶段可能已经完成,且不回滚。

### BrezhnevSort

公开 API 族:提供 `T[]` 和 `List<T>` 两组 `RewriteAsOrdinalSequence` 重载,其中 `T : INumber<T>`。

1. 不比较、筛选或重排输入元素。
2. 输出只由输入长度决定。长度为 `n` 时,结果固定为 `1..n`。
3. 输入元素原值不会被读取,也不会影响结果。
4. 数组重载不修改输入数组,并始终返回新的结果数组。
5. `List<T>` 重载原地把整个列表改写为 `1..n`。
6. `values == null` 时抛 `ArgumentNullException`。
7. 当输入长度超出 `T` 的可表示范围时抛 `OverflowException`。
8. 数组重载异常后输入保持不变;`List<T>` 重载溢出时可能已部分修改,且不回滚。

### TrumpSort

公开 API 族:提供 `T[]` 和 `List<T>` 两组 `ShuffleAndWin` 重载,支持默认随机源和显式 `Random`。

1. 对输入执行一次 Fisher-Yates 随机重排。
2. 不保证结果有序,不删除元素,也不改写元素值。
3. 输出与输入长度一致,元素多重集一致。
4. 数组重载不修改输入数组,并始终返回结果数组,不返回原数组引用。
5. `List<T>` 重载原地随机重排。
6. `random == null` 时使用 `Random.Shared`。
7. 使用相同输入和显式随机种子时,数组重载可复现,列表重载可复现,且两者结果内容一致。
8. `values == null` 或显式传入的 `random == null` 时抛 `ArgumentNullException`;随机源异常原样传播。
9. 数组重载异常后输入保持不变;`List<T>` 重载异常后可能已部分修改,且不回滚。
70 changes: 0 additions & 70 deletions specs/StrangeSort 项目开发规范.md

This file was deleted.

58 changes: 58 additions & 0 deletions specs/StrangeSortTest 测试规范.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# StrangeSortTest 测试规范

## 目标

1. `StrangeSortTest` 的首要职责是防止公开行为漂移和功能实现错误。
2. 测试要以 `specs/StrangeSort 开发规范.md` 内算法行为协议为准,不要只按当前实现去写断言。

## 通用要求

1. 任何算法改动,至少覆盖对应算法的数组重载和 `List<T>` 重载。
2. 任何协议变更,必须在同一次改动中同步更新规范和测试。
3. 禁止为了让测试通过而在实现中硬编码输入、长度、随机种子或比较结果。
4. 随机相关测试必须显式控制随机种子,不要依赖 `Random.Shared` 的即时输出。
5. 异常测试除了断言异常类型,还要断言输入是否被修改。

## 边缘条件测试指南

1. 优先覆盖空输入、单元素输入、重复元素、已满足目标条件的输入和最小可复现输入。
2. 覆盖 `null` 参数、`comparer == null`、`random == null`、非法枚举值、不可比较类型和溢出路径。
3. 区分数组重载与 `List<T>` 重载的输入修改语义、返回引用语义和异常后状态。
4. 如果规范声明了相对顺序、元素多重集、子序列性质、固定过滤区间或固定结果长度,这些都应有直接断言。
5. 文档中的调用示例应尽量有对应测试,避免示例和真实行为脱节。

## 各算法重点

### StalinSort

1. 断言输出是输入子序列,且相对顺序保持不变。
2. 断言数组重载在长度 `0` 或 `1` 时返回原引用,在更长输入时返回新数组。
3. 覆盖默认比较器不可用时的异常,以及 `List<T>` 异常后可能部分修改。

### ThanosSort

1. 断言结果始终是有序子序列。
2. 覆盖 `FloorHalf` 和 `CeilingHalf` 两种删除策略。
3. 使用固定种子验证数组重载可复现、列表重载可复现,以及两者结果一致。
4. 覆盖非法 `RemovalCountStrategy` 和显式 `random == null`。

### EpsteinSort

1. 断言结果只包含 `[0, 18)` 内的值。
2. 对浮点类型覆盖 `NaN`、`-Infinity` 和 `+Infinity`。
3. 断言过滤不受比较器影响,比较器只影响排序结果。
4. 覆盖排序异常时 `List<T>` 可能已经完成过滤的情况。

### BrezhnevSort

1. 断言结果只由输入长度决定,与输入值无关。
2. 断言数组重载始终返回新数组。
3. 覆盖目标类型可表示范围不足时的 `OverflowException`。
4. 覆盖 `List<T>` 溢出时可能部分改写的情况。

### TrumpSort

1. 断言结果长度不变,元素多重集不变。
2. 使用固定种子验证数组重载可复现、列表重载可复现,以及两者结果一致。
3. 断言数组重载始终返回新数组。
4. 覆盖显式 `random == null` 和随机源异常传播。
Loading