C# 使用最大排列对数字进行排序
我想对整数列表进行排序,使它们尽可能分散。假设基数为8,1和7之间的项目顺序应为:{4,6,2,7,1,5,3},根据: 当然,有相当多的歧义,因为6和2与4、0和8的距离相等,所以6和2的具体顺序是不相关的。我试图实现的是首先选择距离0和基数最远的数字,然后选择距离0、基数和第一个数字最远的数字,等等。基数的任何倍数都不会出现,所以我不在乎如何处理 我可以为任何给定的基手动设计排序顺序,但我需要它来为任何大于等于2的基工作。有没有一种聪明/快速的方法来计算这个问题,或者我需要懒洋洋地构建排序映射表并缓存它们以备将来使用C# 使用最大排列对数字进行排序,c#,sorting,C#,Sorting,我想对整数列表进行排序,使它们尽可能分散。假设基数为8,1和7之间的项目顺序应为:{4,6,2,7,1,5,3},根据: 当然,有相当多的歧义,因为6和2与4、0和8的距离相等,所以6和2的具体顺序是不相关的。我试图实现的是首先选择距离0和基数最远的数字,然后选择距离0、基数和第一个数字最远的数字,等等。基数的任何倍数都不会出现,所以我不在乎如何处理 我可以为任何给定的基手动设计排序顺序,但我需要它来为任何大于等于2的基工作。有没有一种聪明/快速的方法来计算这个问题,或者我需要懒洋洋地构建排序
int SortOrder(int radix, int value)
{
int offset = value % radix;
int[] table = {int.MinValue, 4, 2, 6, 0, 5, 1, 3}; // Hand-crafted for base-8
return table[offset];
}
我最初的答案是找到最大增量。要从“出”到“入”,请使用相同的比较但不同的选择:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };//SORT this list for sorted results!
List<double> lowerHalf = new List<double>();
List<double> upperHalf = new List<double>();
for (int i = 0; i < doub.Count; i++)
{
if (i <= (int)Math.Floor((double)doub.Count / 2))
lowerHalf.Add(doub[i]);
else
upperHalf.Add(doub[i]);
}
if (upperHalf.Count < lowerHalf.Count)
{
upperHalf.Insert(0,lowerHalf[lowerHalf.Count-1]);
}
//if(upperHalf[0]==lowerHalf[lowerHalf.Count-1]){double median = lowerHalf[lowerHalf.Count-1]+upperHalf[1])/2;lowerHalf[lowerHalf.Count-1] = median; upperHalf[0]=median;}//use Math.Round or Math.Floor/Ceiling if necessary
for (int i = 0; i < lowerHalf.Count; i++)
{
double deltas = Math.Sqrt(Math.Pow(upperHalf[upperHalf.Count - (i + 1)] - lowerHalf[i], 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1}, {2} is: {0}", deltas, lowerHalf[i], upperHalf[upperHalf.Count - (i+1)]);
}
Console.ReadLine();
或者是数学。Abs或者是一个测试,看看哪个更大——但是这应该给你一个如何开始的想法。如果号码在原始列表中不按顺序排列,也可以在选择之前调用orderby
字面上:
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
double deltas = Math.Sqrt( doub.Select(p => Math.Pow(p - doub.First(), 2)).OrderBy(p => p).Last());
Console.WriteLine("The answer is: {0}",deltas);
Console.ReadLine();
答案是:7
要继续对列表进行排序,请使用:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
//sort doub if necessary
foreach (double num in doub)
{
double deltas = Math.Sqrt(Math.Pow(doub.Select(p => p - num).OrderBy(p => p).Last(), 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1} is: {0}", deltas,num);
}
Console.ReadLine();
平方/平方根有助于我们改变符号和处理消极因素——所以
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };
因为我未能在入站或出站端对列表进行排序,所以没有按顺序排列
运行后,列表答案将包含结果-答案可以访问最低的增量。第一个,答案可以访问最高的增量。最后一个。类似的delta将存在于不同的数字和相同的单位数之间——如果您想消除重复的delta,可以在公式中使用HashSet转换。如果你需要帮助,请告诉我
如果需要存储创建增量的数字以及增量本身,则可以在For/Each循环中使用它们,如Console.WriteLine所示
如果您想在中间带的两侧计算到中间带的范围,最好将列表拆分并成对计算。在一个列表中,将0设为中间值,在第二个列表中,将中间值设为endRange,在第一个列表中计算,在第二个列表中计算。这会让你达到目的,但如果你需要帮助克服最后的困难,请告诉我
希望这有帮助 这并不是问题的答案,因为它不会试图快速找到答案。而是为每个基数构建缓存排序值的字典
#region sorting logic
/// <summary>
/// Maintains a collection of sorting maps for all used number bases.
/// </summary>
private static readonly Dictionary<int, int[]> _sortingTable = new Dictionary<int, int[]>();
private static readonly object _sortingLock = new object();
/// <summary>
/// Compute the sorting key for a given multiple.
/// </summary>
/// <param name="radix">Radix or base.</param>
/// <param name="multiple">Multiple.</param>
/// <returns>Sorting key.</returns>
public static int ComputeSortingKey(int radix, long multiple)
{
if (radix < 2)
throw new ArgumentException("Radix may not be less than 2.");
if (multiple == 0)
return int.MinValue; // multiple=0 always needs to be sorted first, so pick the smallest possible key.
int[] map;
if (!_sortingTable.TryGetValue(radix, out map))
lock (_sortingLock)
{
map = new int[radix];
map[0] = -1; // Multiples of the radix are sorted first.
int key = 0;
HashSet<int> occupancy = new HashSet<int> { 0, radix };
HashSet<int> collection = new HashSet<int>(1.ArrayTo(radix)); // (ArrayTo is an extension method in this project)
while (collection.Count > 0)
{
int maxValue = 0;
int maxDistance = 0;
foreach (int value in collection)
{
int distance = int.MaxValue;
foreach (int existingValue in occupancy)
distance = Math.Min(distance, Math.Abs(existingValue - value));
if (distance > maxDistance)
{
maxDistance = distance;
maxValue = value;
}
}
collection.Remove(maxValue);
occupancy.Add(maxValue);
map[maxValue] = key++;
}
_sortingTable.Remove(radix); // Just in case of a race-condition.
_sortingTable.Add(radix, map);
}
long offset = multiple % radix;
if (offset != 0)
if (multiple < 0)
offset = radix - (Math.Abs(multiple) % radix);
return map[(int)offset];
}
#endregion
什么是p.First表示double?p.First是列表中要排序的第一项,在本例中为nums。nums.Select p=>p.First将从列表中的第一个项目中选择每个项目的增量列表。你可以运行它并检查b4 You dv-答案是7。恐怕你错了-请查看我运行的代码和我编辑的答案中的结果。这个更新的答案如何产生OP的预期结果4、6、2、7、1、5、3我也看不出它有什么帮助。一旦将4确定为距离0和8最远的值,则下一个要拾取的值必须考虑0、8和4。为集合中的每个值预先计算一组距离是没有用的。顺便说一句,我正在使用整数和长整数,而不是双倍整数。不确定这对您的方法是否重要,但至少Pow和Sqrt调用停止有意义。
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
//sort doub if necessary
foreach (double num in doub)
{
double deltas = Math.Sqrt(Math.Pow(doub.Select(p => p - num).OrderBy(p => p).Last(), 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1} is: {0}", deltas,num);
}
Console.ReadLine();
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\TDA_Stream_Interface.dll'. Symbols loaded.
The answer for 0 is: 7
The answer for 1 is: 6
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for 5 is: 2
The answer for 7 is: 0
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };
The answer for 0 is: 7
The answer for -1 is: 8
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for -5 is: 12
The answer for 7 is: 0
#region sorting logic
/// <summary>
/// Maintains a collection of sorting maps for all used number bases.
/// </summary>
private static readonly Dictionary<int, int[]> _sortingTable = new Dictionary<int, int[]>();
private static readonly object _sortingLock = new object();
/// <summary>
/// Compute the sorting key for a given multiple.
/// </summary>
/// <param name="radix">Radix or base.</param>
/// <param name="multiple">Multiple.</param>
/// <returns>Sorting key.</returns>
public static int ComputeSortingKey(int radix, long multiple)
{
if (radix < 2)
throw new ArgumentException("Radix may not be less than 2.");
if (multiple == 0)
return int.MinValue; // multiple=0 always needs to be sorted first, so pick the smallest possible key.
int[] map;
if (!_sortingTable.TryGetValue(radix, out map))
lock (_sortingLock)
{
map = new int[radix];
map[0] = -1; // Multiples of the radix are sorted first.
int key = 0;
HashSet<int> occupancy = new HashSet<int> { 0, radix };
HashSet<int> collection = new HashSet<int>(1.ArrayTo(radix)); // (ArrayTo is an extension method in this project)
while (collection.Count > 0)
{
int maxValue = 0;
int maxDistance = 0;
foreach (int value in collection)
{
int distance = int.MaxValue;
foreach (int existingValue in occupancy)
distance = Math.Min(distance, Math.Abs(existingValue - value));
if (distance > maxDistance)
{
maxDistance = distance;
maxValue = value;
}
}
collection.Remove(maxValue);
occupancy.Add(maxValue);
map[maxValue] = key++;
}
_sortingTable.Remove(radix); // Just in case of a race-condition.
_sortingTable.Add(radix, map);
}
long offset = multiple % radix;
if (offset != 0)
if (multiple < 0)
offset = radix - (Math.Abs(multiple) % radix);
return map[(int)offset];
}
#endregion