【问题标题】:Choosing the right data structure for this problem: circular linked list, list, array or something else为这个问题选择正确的数据结构:循环链表、列表、数组或其他
【发布时间】:2009-06-22 17:34:41
【问题描述】:

我的要求是针对每种类型 T,我有许多元素(在 1-30+ 之间),首先我需要随机项目,然后我需要下一个,当我到达最后一个项目时,它应该返回第一个,依此类推。

所以说T是Icon,集合是Images(实例)。

我想拥有:

// program start:

Icon icon = RandomIcon(); // say 5th one for this case

// user clicks next icon:

icon = current++; (6, 7, 8, 1, 2, ...)

对我来说,循环链表是有意义的,除了我必须做 O(n),其中 n 是随机索引。

我想要最干净,最好的实现,因此问题。

【问题讨论】:

    标签: c# .net performance data-structures


    【解决方案1】:

    另一种可能的解决方案是创建一个链表,其底层数据结构是一个数组。这样,您可以在 O(1) 处进行索引,同时保持“循环”

    public class myLL
    {
        private T[] items;
        private int i;
        private int max_size;
    
        public T GetCurrent() {
            return items[i];
        }
    
        public T GetNext() {
            i = i++ % max_size;
            return items[i];
        }
    }
    

    【讨论】:

    • 如果(由于某种原因)列表大小是可变的,并且事先不知道,List 将具有类似的行为
    【解决方案2】:

    我会考虑在内部使用包含数组或 List 的自定义类,并制作一个从任何索引开始并围绕循环进行枚举的自定义枚举器。

    我认为这比 LinkedList 更好的主要原因与这一行有关:

    Icon icon = RandomIcon(); // say 5th one for this case
    

    从可索引的集合中获取随机项比从链表中获取随机项要容易得多,性能也更高......而且有 30 个元素,无论哪种情况,枚举都会很快。

    要处理循环中的迭代,您只需要这样:

    class CircularlyEnumerableList<T>
    {
        private List<T> list;
    
        // Implement whatever you need for list...
    
        IEnumerable<T> EnumerateFromElement(int index)
        {
            for (int i=index; i<list.Count; ++i)
                 yield return list[i];
    
            for (int i=0; i<index; ++i)
                 yield return list[i];
        }
    }
    

    【讨论】:

    • 谢谢里德。在这种情况下如何调用“GetNextItem”?我必须调用内部 IEnumerable 方法?
    • 谢谢里德。我不知何故以为你会使用foreach。所以在这种情况下,2个for循环比将随机索引代码放在枚举器内要好,对吧?随机索引代码应该在构造函数中吗?我就是这么想的。
    • Joan:我会把它放在一边,这样你就可以拥有你的图标列表,然后做一些你填写一个图标列表的事情,然后随机从中提取。这样您就不需要每次都创建一个新集合 - 只需使用同一个集合,并具有一个新的随机起点。 - 我认为这比尝试使用 foreach 并以这种方式随机化索引要干净得多(也快得多)。
    • 谢谢里德。如果我理解正确,您认为图标列表对所有人都是固定的,对吧?每个项目都有一个与其他项目不同的图标列表。如果这与您的想法不同,它会改变您的回复/想法吗?谢谢。
    • 不一定。不过,如果您愿意,您可以在构造函数中轻松计算随机索引。那么好的事情是您不再需要传递索引 - 它就在那里。不过,我仍然会对集合以及枚举使用相同的方法。
    【解决方案3】:
    • 循环列表不错
    • 由于您有大约 30 个元素(而不像 3000 个),您可以考虑使用索引表而不是链表
      • 如果您的元素没有不断被添加和删除,这将立即生效
    • 如果您已动态插入和删除元素,您仍然可以编写一些代码来处理它(因为,小列表)
    • 如果这一切都适合您,那么剩下的只是 1-N 之间的随机数。

    • 如果您的每个列表的项目数很少,那么实施内衬列表将是一种过度杀戮
    • 但是,如果您选择这样做,您仍然可以承担第一次遍历列表到随机选择的起点的费用

    【讨论】:

      【解决方案4】:

      为什么要使用链表?使用数组并存储当前项目的索引。当调用函数以获取下一项时,增加索引。如果索引大于元素的数量,则将索引设置为零。

      【讨论】:

      • ++ 简单是最好的。令人惊讶的是,复杂的简单事物竟然可以做出来。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-17
      • 2011-04-05
      • 1970-01-01
      相关资源
      最近更新 更多