C# 数组中元素递归相加的最小和每次两个
我有一个整数数组。每个元素的值表示处理文件所花费的时间。文件处理包括一次合并两个文件。找到处理所有文件所需的最短时间的算法是什么。例如-{3,5,9,12,14,18} 处理时间可计算为—— 案例1)— 所以处理的总时间是61+35+26+17+8=147 案例2)- 这次总时间为61+40+23+17+21=162C# 数组中元素递归相加的最小和每次两个,c#,algorithm,recursion,data-structures,recursive-datastructures,C#,Algorithm,Recursion,Data Structures,Recursive Datastructures,我有一个整数数组。每个元素的值表示处理文件所花费的时间。文件处理包括一次合并两个文件。找到处理所有文件所需的最短时间的算法是什么。例如-{3,5,9,12,14,18} 处理时间可计算为—— 案例1)— 所以处理的总时间是61+35+26+17+8=147 案例2)- 这次总时间为61+40+23+17+21=162 在我看来,连续排序数组并添加至少两个元素是最小值的最佳选择,如案例1所示。我的逻辑正确吗?如果不是,那么以最佳性能实现这一点的正确且最简单的方法是什么?否,这是多相合并的最小值:其
在我看来,连续排序数组并添加至少两个元素是最小值的最佳选择,如案例1所示。我的逻辑正确吗?如果不是,那么以最佳性能实现这一点的正确且最简单的方法是什么?否,这是多相合并的最小值:其中
N
是带宽(可以同时合并的文件数),那么您希望在每一步合并最小的(N-1)文件。但是,对于这个更普遍的问题,您希望尽可能长时间地延迟较大的文件--您可能希望提前一两步合并少于(N-1)个文件,有点像在淘汰赛中“再见”。您希望后面的所有步骤都涉及完整(N-1)文件
例如,给定N=4和文件1、6、7、8、14、22
:
早期合并:
[22], 14, 22
[58]
total = 80
后期合并:
[14], 8, 14, 22
[58]
total = 72
一旦您有了排序列表,因为您只删除了两个最小项并用一个替换它们,所以执行排序插入并将新项放置在正确的位置比重新排序整个列表更有意义。然而,这只节省了一小部分时间——大约快了1% 我的方法
CostOfMerge
不假定输入是列表
,但如果是,您可以删除转换列表
步骤
public static class IEnumerableExt {
public static int CostOfMerge(this IEnumerable<int> psrc) {
var src = psrc.ToList();
src.Sort();
while (src.Count > 1) {
var sum = src[0]+src[1];
src.RemoveRange(0, 2);
var index = src.BinarySearch(sum);
if (index < 0)
index = ~index;
src.Insert(index, sum);
total += sum;
}
return total;
}
}
公共静态类IEnumerableExt{
公共静态整数成本(此IEnumerable psrc){
var src=psrc.ToList();
src.Sort();
而(src.Count>1){
var sum=src[0]+src[1];
src.removange(0,2);
var index=src.BinarySearch(总和);
如果(指数<0)
索引=~index;
src.插入(索引、总和);
总数+=总和;
}
返回总数;
}
}
在这里,您可以应用以下逻辑来获得所需的输出
公共类最小和{
私有静态整数getFirstMinimum(ArrayList列表){
整数最小值=整数最大值;
对于(int i=0;i,正如在其他答案中已经讨论过的,最好的策略是每次迭代都以最小的成本处理这两个项目。因此,剩下的唯一问题是如何有效地每次处理这两个最小的项目
由于您要求获得最佳性能,我无耻地从NetMage获得了算法,并对其进行了修改,使其在我的测试用例中的速度提高了大约40%(感谢和+1到)
其想法是在单个阵列上就地工作。
每次迭代都会将起始索引增加1,并移动数组中的元素,为当前迭代的总和留出空间
public static long CostOfMerge2(this IEnumerable<int> psrc)
{
long total = 0;
var src = psrc.ToArray();
Array.Sort(src);
var i = 1;
int length = src.Length;
while (i < length)
{
var sum = src[i - 1] + src[i];
total += sum;
// find insert position for sum
var index = Array.BinarySearch(src, i + 1, length - i - 1, sum);
if (index < 0)
index = ~index;
--index;
// shift items that come before insert position one place to the left
if (i < index)
Array.Copy(src, i + 1, src, i, index - i);
src[index] = sum;
++i;
}
return total;
}
显示的NetMage CostOfMerge配置的结果:
Cost of Merge: 3670570720
Time of Merge: 00:00:15.4472251
我的麦加成本2:
Cost of Merge: 3670570720
Time of Merge: 00:00:08.7193612
当然,详细的数字取决于硬件,差异可能更大,也可能更小,这取决于一堆东西。你的问题有点难以回答……第一部分似乎是一个简单的是或不是问题(“这是对的吗?”),第二部分主要是基于意见的(“有更好的算法来实现这一点吗?”)没有指定“更好”的设计目标。我认为它并不真正符合stackoverflow的格式。请重新思考您的实际问题。我编辑了这个问题。我只是在寻找正确和最快速的逻辑或伪代码。对于N=2,这是否适用?否:N-1
=1,因此它与您已经在做的事情等效。
public static long CostOfMerge2(this IEnumerable<int> psrc)
{
long total = 0;
var src = psrc.ToArray();
Array.Sort(src);
var i = 1;
int length = src.Length;
while (i < length)
{
var sum = src[i - 1] + src[i];
total += sum;
// find insert position for sum
var index = Array.BinarySearch(src, i + 1, length - i - 1, sum);
if (index < 0)
index = ~index;
--index;
// shift items that come before insert position one place to the left
if (i < index)
Array.Copy(src, i + 1, src, i, index - i);
src[index] = sum;
++i;
}
return total;
}
static void Main(string[] args)
{
var r = new Random(10);
var testcase = Enumerable.Range(0, 400000).Select(x => r.Next(1000)).ToList();
var sw = Stopwatch.StartNew();
long resultCost = testcase.CostOfMerge();
sw.Stop();
Console.WriteLine($"Cost of Merge: {resultCost}");
Console.WriteLine($"Time of Merge: {sw.Elapsed}");
Console.ReadLine();
}
Cost of Merge: 3670570720
Time of Merge: 00:00:15.4472251
Cost of Merge: 3670570720
Time of Merge: 00:00:08.7193612