【发布时间】:2020-09-29 17:51:45
【问题描述】:
我正在寻找任何命令式编程语言中的算法,通过在原始列表中移动来将唯一列表重新排序到另一个列表。
输入:
items = [a, b, c, d, e]
sampleItems = [b, c, e, d, a]
输出:
items = [b, c, e, d, a]
items 和 sampleItems 中的项目集是相等的。
应通过移动原始列表(items)来执行重新排序。
void Move(int oldIndex, int newIndex)
{
Item item = items[oldIndex];
items.RemoveAt(oldIndex);
items.Insert(item, newIndex);
}
所以 items 列表在所有重新排序期间保存了它的唯一性。
算法应该尽可能高效,不创建字典等额外的数据结构,并且具有最少的移动量和最小的复杂性。
蛮力方法是按新索引进行冒泡排序。但它需要创建字典(键:项目,值:新索引)或样本列表上的大量枚举(sampleItems)。我正在寻找更有效的方法。
我尝试了以下算法(C#),它可以正常工作,但效率不高,因为它创建了一个字典并且具有 O(n^2) 复杂度。处理 10001 个项目大约需要 9 秒。很慢:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApp14
{
class Program
{
static void Main(string[] args)
{
ObservableCollection<Item> items = new ObservableCollection<Item>();
int count = 10001;
for (int i = 0; i < count; i++)
{
items.Add(new Item(i));
}
Random random = new Random();
ObservableCollection<Item> sampleItems = new ObservableCollection<Item>(items.OrderBy(i => random.Next()));
Stopwatch stopwatch = Stopwatch.StartNew();
Dictionary<Item, int> oldIndeces = new Dictionary<Item, int>();
for (int i = 0; i < count; i++)
{
oldIndeces.Add(items[i], i);
}
for (int i = 0; i < count; i++)
{
int oldIndex = oldIndeces[sampleItems[i]];
items.Move(oldIndex, i);
for (int j = 0; j < count; j++)
{
Item item = items[j];
int oldIndex1 = oldIndeces[item];
if (oldIndex1 <= oldIndex)
oldIndeces[item] = oldIndex1 + 1;
}
}
Debug.Assert(sampleItems.SequenceEqual(items));
stopwatch.Stop();
Console.WriteLine($"Done in {stopwatch.ElapsedMilliseconds}ms");
Console.ReadLine();
}
}
public class Item
{
public Item(int num)
{
Num = num;
}
private int Num { get; }
#region Overrides of Object
public override string ToString()
{
return Num.ToString();
}
#endregion
}
}
输出:
在 9123 毫秒内完成
【问题讨论】:
标签: list algorithm sorting language-agnostic unique