结论
如有错,请大佬批评指正~
稳定排序:
- 单次排序数据较少,用插入排序
- 单次排序数据较大,用List.Sort的定制版(自己改一下)
可以参考下图,几百以内可定义为数据较少,上千上万可认为数据较大
(图中单位为ms)
1.起因
因为List<T>
的方便性,我在项目中常常使用,虽说知道有一定性能消耗,但没有具体研究过,直到(直到踩坑 )…在一个需要频繁排序,且需要是稳定的情况下,List.Sort()不再继续适用了。
2.可能的解决方法
一番查资料、翻书后,要么使用稳定且较快速的插入排序(含改进和二分搜索版),要么对List.Sort()进行一些限制调整。
2.0 自定义数据结构
插入排序是稳定的,嗯,但它的改进版、二分法查找版是稳定的吗?List.Sort是稳定的吗,书本和网络上有着很多混淆的答案。
对代码进行逻辑分析是第一步,但究竟什么时候稳定什么时候不稳定(稳定和不稳定是可以转换的),还是实践出真知,我们建立测试用数据结构,是否稳定一测便知:
public class MyData
{
public int data;
public int idx;
public MyData(int data)
{
this.data = data;
idx = GetIdx();
}
}
public static int Idx = 0;
static int GetIdx()
{
return Idx++;
}
这里的 idx 用来检查排序前后,相同元素的相对顺序是否被改变了
2.1 插入排序
//改进版
static void InsertionSort_noSwap(List<MyData> arr)
{
MyData temp = null;
int j;
for (int i = 1; i < arr.Count; i++)
{
temp = arr[i];
j = i - 1;
while (j >= 0 && temp.data < arr[j].data)
{
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = temp;
}
}
//二分搜索法
static void InsertionSort_BinarySearch(MyData[] arr)
{
for (int i = 1; i < arr.Length; i++)
{
MyData temp = arr[i];
int low = 0;
int high = i - 1;
int mid = -1;
while (low <= high)
{
mid = low + (high - low) / 2;
if (arr[mid].data > temp.data)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for (int j = i - 1; j >= low; j--)
{
arr[j + 1] = arr[j];
}
arr[low] = temp;
}
}
2.2 List.Sort()自定义
对数据结构进行扩充,定义相同元素的处理方法
public class MyData : IComparable
{
public int data;
public int idx;
public MyData(int data)
{
this.data = data;
idx = GetIdx();
}
public int CompareTo(object obj)
{
int result = 1;
if (obj != null && obj is MyData)
{
var myData = (MyData)obj;
result = this.data.CompareTo(myData.data);
if (result == 0)
result = this.idx.CompareTo(myData.idx);
}
return result;
}
}
//调用时和普通的一样(升序)
List.Sort();
3.确定解决方案
生成多个随机数组,进行时间消耗测试
测试结果及结论见文章开头。
所以针对项目,这种单次数据量小,但是会频繁排序的情况,还是使用插入排序较好。
优化后排序消耗是原来的1/2 ~ 1/3
运行的结果,这里只排了3次,每次10个(快速排序作为不稳定的排序,也放在里面作为对比)
Ps:做需求时间紧,最开始用的老方法,时间和空间消耗妥妥的大:
static List<int> s_rank = new List<int>();
static MyData[] m_temp;
/// <summary>
/// 3_Old
/// 老方法
/// </summary>
/// <param name="arr"></param>
static void OldSort(MyData[] arr)
{
int len = arr.Length;
int idx = 0;
s_rank.Clear();
m_temp = new MyData[len];
for (int i = 0; i < len; ++i)
{
if (s_rank.Contains(arr[i].data) == false)
{
s_rank.Add(arr[i].data);
}
}
s_rank.Sort();
for (int s_idx = 0; s_idx < s_rank.Count; ++s_idx)
{
for (int i = 0; i < len; ++i)
{
if (arr[i].data == s_rank[s_idx])
{
m_temp[idx] = arr[i];
++idx;
}
}
}
for (int i = 0; i < m_temp.Length; ++i)
{
arr[i] = m_temp[i];
}
}