【发布时间】:2017-07-31 21:10:08
【问题描述】:
情况:
我有链接到其他页面的“页面”,这些页面将存储在数据库中,因此要存储 1 我需要先存储其链接页面(对于外键)。
所以我需要做的是找到从所选页面链接到根目录的所有页面。
示例:
A - 链接到 - B & C & D
B - 链接到 - C & F
C - 链接到 - E & F
D - 链接到 - B & C
E - 链接到 - F
F - 链接到 - 没有链接
本例中正确的嵌套顺序是:
F - E - C - B - D - A
请注意,我通常有近 30 个页面,链接遍布各处
问题:
我已经有了可以工作的代码,但是从每个页面获取链接需要一段时间(平均 800 毫秒),所以我想尽可能少地检查页面的链接。
代码示例:(非生产代码)
static class Program
{
public static Dictionary<int, int[]> Dict = new Dictionary<int, int[]>();
private static int hitcount = 0;
static void Main(string[] args)
{
//Example data
Stopwatch sw = new Stopwatch();
sw.Start();
Dict.Add( 1, new int[]{2, 3, 4});
Dict.Add(2, new int[] {3, 6 });
Dict.Add(3, new int[] { 5, 6 });
Dict.Add(4, new int[] { 2, 3 });
Dict.Add(5, new int[] { 6 });
Dict.Add(6, new int[] {});
var links = GetAllLinks( 1 );
foreach ( var link in links )
{
Console.WriteLine(link.ToString());
}
sw.Stop();
Console.WriteLine("MS:" + sw.ElapsedMilliseconds + " - " + hitcount);
Console.ReadKey();
}
private static List<int> GetLinksFromKey(int key)
{
//This usually takes avg 800ms so sleep here
//This is the BottleNeck, the more often its called longer it will take
Thread.Sleep( 800 );
hitcount++;
return Dict[key].ToList();
}
private static List<int> GetAllLinks(int key)
{
var allPages = new List<int>();
var pages = new List<int>();
pages.Add(key);
while (true)
{
var i = 0;
var newP = new List<int>();
newP.AddRange(pages);
foreach (var page in pages.Distinct())
{
if (allPages.Contains(page))
{
continue;
}
newP.AddRange(GetLinksFromKey(page));
i++;
allPages.Add(page);
}
pages = new List<int>(newP);
if (i == 0)
{
break;
}
}
return SortLinks(new List<int>(allPages.Distinct()));
}
private static List<int> SortLinks(List<int> pagesToSort)
{
var sortedPages = new List<int>();
var hasReference = new List<int>();
while (sortedPages.Count != pagesToSort.Count)
{
foreach (var page in pagesToSort)
{
if (sortedPages.Contains(page))
{
continue;
}
var links = GetLinksFromKey(page);
if (new List<int>(links.Distinct()).RemoveListFromList(sortedPages).Count == 0)
{
sortedPages.Add(page);
}
else
{
hasReference.Add(page);
}
if (hasReference.Distinct().Count() == pagesToSort.Distinct().Count())
{
Console.WriteLine("There are circular references, can't find the root.");
return sortedPages;
}
}
}
return sortedPages;
}
private static List<int> RemoveListFromList(this List<int> mainList, List<int> removeList)
{
foreach (var item in removeList)
{
if (mainList.Contains(item))
{
mainList.Remove(item);
}
}
return mainList;
}
}
我将此代码作为我的嵌套情况的示例,我这样做是为了使它与字典而不是页面一起使用。为此使用字典非常快,但我知道瓶颈在哪种方法中,所以如果有人有我使用它的解决方案,那就太好了。
问题:
反正有没有让这更有效?我觉得我做错了。
如果没有更快的方法来做到这一点,我也很高兴听到。
如果你可以让 hitcount
【问题讨论】:
-
有一种方法可以使它成为 O(N) - 以任何顺序处理页面。每次您找到指向不存在页面的链接时,请在数据库中创建一个占位符条目。然后,当您最终到达链接页面时,只需更新占位符即可。
-
@RB 为什么不能是 O(N)?使用递归似乎很简单......
-
我需要在存储之前找到嵌套顺序等,因为可能存在我们不允许的循环引用:)
-
@xanatos 是的,对不起,你是对的。我的方式内存效率更高,但不一定性能更高。
标签: c# algorithm sorting recursion