地精排序(Gnome Sort)是一种简单、直观的比较型排序算法,类似于插入排序,但通过“向前冒泡”或“向后移动”来逐步将元素移到正确位置
地精排序(Gnome Sort)是一种简单、直观的比较型排序算法,类似于插入排序,但通过“向前冒泡”或“向后移动”来逐步将元素移到正确位置。它的时间复杂度为平均和最坏情况
O(n^2)
,最好情况(部分有序)接近 ( O(n) ),空间复杂度为 ( O(1) )。
地精排序因其实现简单且适合小型数据集,特别适用于资源受限或需要简单维护的场景。以下将详细描述地精排序的原理,结合半导体车间调度、测试机、MES、EAP等场景的应用,提供C#代码实现、示例和测试用例,并与并行圈排序、计数排序、梳排序、BST排序、优化桶排序、优化冒泡排序及加权有向稠密图进行对比。
1. 地精排序的原理与优化
1.1 地精排序原理地精排序的工作方式类似于一个“地精”在整理一排花盆:从左到右检查每个元素,若当前元素比前一个元素小,则交换并向后退一步检查;若不小于,则继续向前移动。算法步骤如下:
- 初始化:从数组索引0开始,设置指针 i。
- 比较与交换:
- 若 i == 0 或 array[i] >= array[i-1],则向前移动(i++)。
- 若 array[i] < array[i-1],交换 array[i] 和 array[i-1],并向后退一步(i--)。
- 终止:当 i 到达数组末尾时,排序完成。
特点:
- 简单实现:代码短小,易于理解和维护。
- 原地排序:仅需常数额外空间。
- 不稳定排序:相等元素的相对顺序可能改变。
- 部分有序优化:对部分有序数据效率较高,接近 ( O(n) )。
1.2 优化策略
- 提前终止:若一次循环未发生交换,数组已有序,可提前退出。
- 并行比较:在多核环境中并行处理子数组的比较和交换(需同步机制)。
- 批量比较:对部分有序数据,检测连续有序段,跳过不必要的比较。
- 重复值优化:记录重复值,减少比较次数(需额外空间)。
- 向量化:对小型数据集,利用SIMD指令(如SSE)加速比较(需底层优化)。
1.3 地精排序在半导体场景中的适用性地精排序适合小型数据集和资源受限环境,在半导体制造中有以下应用:
- 半导体车间调度:对少量晶圆批次按测试时间或优先级排序,适合嵌入式控制器。
- 应用:对20个晶圆批次按测试时间排序,优化调度。
- 示例:为测试机调度10个批次,按优先级排序。
- 测试机分配:对小型批次集按优先级排序,适合写操作成本高的场景。
- 应用:快速排序批次,减少内存写入。
- 示例:为测试机分配15个批次,按测试时间排序。
- MES中的任务调度:对少量生产任务按优先级或执行时间排序,适合简单实现。
- 应用:优化任务执行顺序,减少存储操作。
- 示例:对MES中10个任务按优先级排序。
- EAP中的数据处理:对少量通信请求按优先级排序,适合资源受限环境。
- 应用:快速排序请求,优化通信路径。
- 示例:对MES发往测试机的20个指令按优先级排序。
1.4 最适应的场景
- 小型数据集:适合
n<100n < 100
的数据集,效率与冒泡排序相当。n < 100 - 资源受限环境:空间复杂度 ( O(1) ),适合测试机控制器等嵌入式系统。
- 部分有序数据:接近 ( O(n) ) 的性能,适合半导体场景中的动态任务。
- 简单实现需求:代码简单,易于维护,适合快速开发。
1.5 与其他排序算法和加权有向稠密图的对比
- 地精排序:
- 时间复杂度:平均
O(n2)O(n^2)
,最好 ( O(n) ).O(n^2) - 空间复杂度:( O(1) ).
- 适用场景:小型数据集、部分有序数据、资源受限环境。
- 时间复杂度:平均
- 并行圈排序:
- 时间复杂度:
O(n2)O(n^2)
,并行化减少实际运行时间。O(n^2) - 空间复杂度:( O(1) )(不计并发结构)。
- 适用场景:写操作成本高、小型数据集、多核环境。
- 对比:地精排序实现更简单,适合单线程;并行圈排序适合多核且写操作受限。
- 时间复杂度:
- 计数排序:
- 时间复杂度:
O(n+k)O(n + k)
.O(n + k) - 空间复杂度:( O(k) ).
- 适用场景:有限值范围、大规模数据、稳定排序。
- 对比:计数排序效率更高,适合整数范围数据;地精排序适合小型通用数据。
- 时间复杂度:
- 梳排序:
- 时间复杂度:平均接近
O(nlogn)O(n \log n)
,最坏O(n \log n)O(n2)O(n^2)
.O(n^2) - 空间复杂度:( O(1) ).
- 适用场景:中小规模数据、部分有序数据。
- 对比:梳排序效率高于地精排序,适合稍大数据规模。
- 时间复杂度:平均接近
- BST排序:
- 时间复杂度:平均
O(nlogn)O(n \log n)
,最坏O(n \log n)O(n2)O(n^2)
.O(n^2) - 空间复杂度:( O(n) ).
- 适用场景:动态数据、中到大规模数据。
- 对比:BST排序支持动态插入;地精排序空间效率高,适合静态数据。
- 时间复杂度:平均
- 优化桶排序:
- 时间复杂度:平均
O(n+k)O(n + k)
,最坏O(n + k)O(n2)O(n^2)
.O(n^2) - 空间复杂度:
O(n+k)O(n + k)
.O(n + k) - 适用场景:均匀分布数据、中到大规模数据。
- 对比:桶排序适合均匀分布数据;地精排序适合小型数据。
- 时间复杂度:平均
- 优化冒泡排序:
- 时间复杂度:平均
O(n2)O(n^2)
,最优 ( O(n) ).O(n^2) - 空间复杂度:( O(1) ).
- 适用场景:小型数据集、部分有序数据.
- 对比:地精排序与冒泡排序效率相当,代码更简洁。
- 时间复杂度:平均
- 加权有向稠密图:
- 时间复杂度:Floyd-Warshall
O(V3)O(V^3)
,PrimO(V^3)O(V2)O(V^2)
.O(V^2) - 空间复杂度:
O(V2)O(V^2)
.O(V^2) - 适用场景:复杂单向依赖网络。
- 结合使用:用Floyd-Warshall计算任务依赖路径,再用地精排序对路径长度排序。
- 时间复杂度:Floyd-Warshall
2. C#实现地精排序以下是C#实现的地精排序,包含提前终止优化,支持通用类型(通过IComparable接口),适用于半导体场景中的任务或批次排序。2.1 地精排序实现csharp
using System;
public class GnomeSort
{
// 地精排序
public static void Sort<T>(T[] array) where T : IComparable<T>
{
if (array == null || array.Length <= 1) return;
int i = 0;
bool swapped = false;
while (i < array.Length)
{
if (i == 0 || array[i].CompareTo(array[i - 1]) >= 0)
{
// 向前移动
if (swapped && i == array.Length - 1)
break; // 提前终止
i++;
swapped = false;
}
else
{
// 交换并后退
T temp = array[i];
array[i] = array[i - 1];
array[i - 1] = temp;
i--;
swapped = true;
}
}
}
}
优化点:
- 提前终止:使用swapped标志,若无交换且到达数组末尾,提前退出。
- 原地排序:空间复杂度 ( O(1) )。
- 通用类型:支持自定义对象排序,适用于晶圆批次等场景。
- 简单实现:代码短小,易于维护。
扩展建议:
- 并行比较:将数组分区,使用Parallel.For并行处理子数组(需同步机制)。
- 重复值优化:使用哈希表记录重复值,减少比较(空间复杂度增至 ( O(n) ))。
- 向量化:使用SIMD指令加速比较(需底层支持)。
2.2 半导体车间调度示例假设一个半导体车间有10个晶圆批次,需按测试时间排序后分配给测试机。以下示例使用地精排序。csharp
using System;
class Program
{
// 晶圆批次类
public class WaferBatch : IComparable<WaferBatch>
{
public int Id { get; set; }
public double TestTime { get; set; } // 测试时间(分钟)
public WaferBatch(int id, double testTime)
{
Id = id;
TestTime = testTime;
}
public int CompareTo(WaferBatch other)
{
return TestTime.CompareTo(other.TestTime);
}
public override string ToString()
{
return $"批次{Id} (测试时间: {TestTime}分钟)";
}
}
static void Main()
{
// 创建晶圆批次数组
WaferBatch[] batches = new WaferBatch[]
{
new WaferBatch(1, 10.5),
new WaferBatch(2, 55.2),
new WaferBatch(3, 25.7),
new WaferBatch(4, 80.1),
new WaferBatch(5, 35.9),
new WaferBatch(6, 15.3),
new WaferBatch(7, 65.4),
new WaferBatch(8, 45.8),
new WaferBatch(9, 90.2),
new WaferBatch(10, 5.1)
};
// 使用地精排序
Console.WriteLine("排序前:");
foreach (var batch in batches)
{
Console.WriteLine(batch);
}
GnomeSort.Sort(batches);
Console.WriteLine("\n按测试时间升序排序后:");
foreach (var batch in batches)
{
Console.WriteLine(batch);
}
}
}
输出:
排序前:
批次1 (测试时间: 10.5分钟)
批次2 (测试时间: 55.2分钟)
批次3 (测试时间: 25.7分钟)
批次4 (测试时间: 80.1分钟)
批次5 (测试时间: 35.9分钟)
批次6 (测试时间: 15.3分钟)
批次7 (测试时间: 65.4分钟)
批次8 (测试时间: 45.8分钟)
批次9 (测试时间: 90.2分钟)
批次10 (测试时间: 5.1分钟)
按测试时间升序排序后:
批次10 (测试时间: 5.1分钟)
批次1 (测试时间: 10.5分钟)
批次6 (测试时间: 15.3分钟)
批次3 (测试时间: 25.7分钟)
批次5 (测试时间: 35.9分钟)
批次8 (测试时间: 45.8分钟)
批次2 (测试时间: 55.2分钟)
批次7 (测试时间: 65.4分钟)
批次4 (测试时间: 80.1分钟)
批次9 (测试时间: 90.2分钟)
说明:地精排序通过向前冒泡和向后移动逐步整理批次,代码简单,适合小型批次集。2.3 测试用例以下是针对地精排序的测试用例,使用NUnit框架验证正确性和性能。测试用例1:正常排序
- 输入:数组 [10.5, 55.2, 25.7, 80.1, 35.9]
- 预期输出:[10.5, 25.7, 35.9, 55.2, 80.1]
- 测试代码:
csharp
using NUnit.Framework;
[TestFixture]
public class GnomeSortTests
{
[Test]
public void TestNormalSort()
{
double[] array = { 10.5, 55.2, 25.7, 80.1, 35.9 };
double[] expected = { 10.5, 25.7, 35.9, 55.2, 80.1 };
GnomeSort.Sort(array);
Assert.AreEqual(expected, array);
}
}
测试用例2:空数组
- 输入:空数组 []
- 预期输出:[]
- 测试代码:
csharp
[Test]
public void TestEmptyArray()
{
double[] array = {};
double[] expected = {};
GnomeSort.Sort(array);
Assert.AreEqual(expected, array);
}
测试用例3:单一元素
- 输入:数组 [50.0]
- 预期输出:[50.0]
- 测试代码:
csharp
[Test]
public void TestSingleElement()
{
double[] array = { 50.0 };
double[] expected = { 50.0 };
GnomeSort.Sort(array);
Assert.AreEqual(expected, array);
}
测试用例4:自定义对象排序
- 输入:晶圆批次数组 [批次1(10.5), 批次2(55.2), 批次3(25.7)]
- 预期输出:[批次1(10.5), 批次3(25.7), 批次2(55.2)]
- 测试代码:
csharp
[Test]
public void TestCustomObjectSort()
{
var batches = new[]
{
new Program.WaferBatch(1, 10.5),
new Program.WaferBatch(2, 55.2),
new Program.WaferBatch(3, 25.7)
};
var expected = new[]
{
new Program.WaferBatch(1, 10.5),
new Program.WaferBatch(3, 25.7),
new Program.WaferBatch(2, 55.2)
};
GnomeSort.Sort(batches);
for (int i = 0; i < batches.Length; i++)
{
Assert.AreEqual(expected[i].Id, batches[i].Id);
Assert.AreEqual(expected[i].TestTime, batches[i].TestTime);
}
}
测试用例5:部分有序数据
- 输入:数组 [5.0, 7.0, 8.0, 12.0, 10.0]
- 预期输出:[5.0, 7.0, 8.0, 10.0, 12.0]
- 测试代码:
csharp
[Test]
public void TestPartiallySorted()
{
double[] array = { 5.0, 7.0, 8.0, 12.0, 10.0 };
double[] expected = { 5.0, 7.0, 8.0, 10.0, 12.0 };
GnomeSort.Sort(array);
Assert.AreEqual(expected, array);
}
测试用例6:重复值
- 输入:数组 [5, 5, 3, 8, 5]
- 预期输出:[3, 5, 5, 5, 8]
- 测试代码:
csharp
[Test]
public void TestDuplicateValues()
{
int[] array = { 5, 5, 3, 8, 5 };
int[] expected = { 3, 5, 5, 5, 8 };
GnomeSort.Sort(array);
Assert.AreEqual(expected, array);
}
运行测试:需在项目中添加NUnit包(NUnit和NUnit3TestAdapter)。
3. 与加权有向稠密图的结合在半导体制造场景中,地精排序可与加权有向稠密图结合:
- 场景:使用Floyd-Warshall算法计算所有工序间的最短路径,得到路径长度列表。地精排序对路径长度排序,优化调度顺序。
- 示例代码:
csharp
public void ScheduleWithGraphAndGnomeSort(WeightedDirectedDenseGraph graph, int start)
{
try
{
var (distances, _) = graph.FloydWarshall();
var pathLengths = new List<(int end, double length)>();
for (int i = 0; i < distances.GetLength(0); i++)
{
if (distances[start, i] != double.MaxValue && start != i)
pathLengths.Add((i, distances[start, i]));
}
// 使用地精排序
var lengthArray = pathLengths.ToArray();
GnomeSort.Sort(lengthArray);
Console.WriteLine($"从工序{start}到其他工序的最短路径(按长度排序):");
foreach (var (end, length) in lengthArray)
{
Console.WriteLine($"到工序{end}:{length} 分钟");
}
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Floyd-Warshall错误:{ex.Message}");
}
}
应用:在MES中,计算从清洗工序到其他工序的最短路径后,用地精排序按路径长度排序,优先调度短路径任务,适合小型数据集。
4. 总结
- 地精排序的应用:
- 半导体车间调度:对少量晶圆批次按测试时间排序,适合嵌入式系统。
- 测试机分配:对小型批次集按优先级排序,减少内存操作。
- MES:对少量任务按优先级排序,适合简单实现。
- EAP:对少量通信请求按优先级排序,适合资源受限环境。
- 最适应场景:小型数据集(n < 100)、部分有序数据、资源受限环境。
- C#实现:提供地精排序实现,包含提前终止优化,支持通用类型,适用于晶圆批次排序。
- 测试用例:覆盖正常排序、空数组、单一元素、自定义对象、部分有序数据和重复值,确保代码健壮性。
- 与并行圈排序的对比:
- 地精排序:实现简单,适合单线程小型数据。
- 并行圈排序:写入次数最少,适合多核且写操作成本高。
- 与计数排序的对比:
- 地精排序:时间复杂度
O(n2)O(n^2)
,空间复杂度 ( O(1) ),适合通用小型数据。O(n^2) - 计数排序:时间复杂度
O(n+k)O(n + k)
,空间复杂度 ( O(k) ),适合值范围小的大数据集。O(n + k)
- 地精排序:时间复杂度
- 与梳排序的对比:
- 地精排序:代码更简洁,适合小型数据。
- 梳排序:效率高于地精排序,适合稍大数据规模。
- 与BST排序的对比:
- 地精排序:空间效率高,适合静态数据。
- BST排序:支持动态插入,适合实时场景。
- 与优化桶排序的对比:
- 地精排序:空间复杂度 ( O(1) ),适合小型数据。
- 优化桶排序:效率更高,适合均匀分布数据。
- 与优化冒泡排序的对比:
- 地精排序:实现更简洁,效率相当。
- 优化冒泡排序:适合部分有序小型数据。
- 与加权有向稠密图的结合:
- 图算法(如Floyd-Warshall)解决依赖关系和路径优化。
- 地精排序对图算法结果(如路径长度)排序,适合小型数据集。
优化建议:
- 实现并行比较,分区处理子数组,适合多核环境。
- 添加重复值优化,使用哈希表(增加空间复杂度)。
- 集成MES数据库接口,支持实时任务排序。
如果需要进一步扩展(例如并行地精排序、浮点数支持、与其他排序算法或图算法结合),请提供具体需求,我可以提供更详细的实现!
更多推荐
所有评论(0)