8

通过数组(或列表、链接列表、字典等)的迭代速度是否取决于数据类型?

示例:一个 10 个布尔值的数组与一个 10 个整数的数组?

4

3 回答 3

2

是的,数据类型很重要。它与迭代无关;它与数据类型有关。

值类型

Anint的长度为 4 个字节。Adecimal的长度为 16 个字节。所以 adecimal是 a 的 4 倍int。每次从数组中检索一个值时,都会复制该值。如果decimal复制了 16 个字节。(在引用类型的情况下,引用被复制,通常为 4 或 8 个字节)。复制更多字节只会减慢迭代速度。

拳击

如果你遍历一个集合,你也有可能改变类型。例如:

foreach(object o in new int[] { 1,2,3 })
     ....

这会将每一个都装箱int到一个object. 这需要时间。这与迭代无关,它与您正在拳击这一事实有关。

铸件

最后一个示例:您还必须在其中投射数组:

foreach(Person p in new object[] { ... })
     ....

铸造也需要额外的时间。

编辑

一些时间测量来支持我的主张:

以毫秒为单位的时间。 数组大小为 10,000。 迭代次数也是 10,000。

于 2013-05-11T08:23:02.743 回答
1

如果需要,请运行下面的代码,但这里有一个快速比较。它所做的只是遍历数组/列表,并将临时变量设置为该索引中的值。

第三轮,高优先级 增加了一些类型

请注意,现在运行时以某种方式 Int 性能受到了打击......不知道为什么......但它也会在重复运行时发生......

    namespace Iterating_types
    {
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
class Program
    {
        static void Main(string[] args)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;

            Stopwatch watch = new Stopwatch();
            int UPPER = 1000000;
            int[] int_arr = Enumerable.Range(1, UPPER).ToArray();
            List<int> int_list = Enumerable.Range(1, UPPER).ToList();

            Int32[] int32_arr = Enumerable.Range(1, UPPER).ToArray();

            Int64[] int64_arr = new Int64[UPPER]; 

            IntObject[] intobject_arr = new IntObject[UPPER];
            List<IntObject> intobject_list = new List<IntObject>();

            string[] string_arr = new string[UPPER];
            List<string> string_list = new List<string>();

            bool[] bool_arr = new bool[UPPER];
            Boolean[] boolean_arr = new Boolean[UPPER];
            List<bool> bool_list = new List<bool>();
            List<Boolean> boolean_list = new List<Boolean>();
            // Initializing some of the above
            for (int i = 0; i < UPPER; i++)
            {
                int64_arr[i] = (Int64) i;
                string_arr[i] = i.ToString();
                string_list.Add(i.ToString());
                intobject_arr[i] = new IntObject(i);
                intobject_list.Add(new IntObject(i));
                bool_arr[i] = (i%2 ==0);
                boolean_arr[i] = (i%2 ==0);
                bool_arr[i] = (i%2 ==0);
                bool_list.Add(i%2 ==0);

                boolean_list.Add(i%2 == 0);
            }

            Console.WriteLine("Iterations: {0}{1}", UPPER, Environment.NewLine);
            Console.WriteLine("Thread priority: {0}", Thread.CurrentThread.Priority);
            Console.WriteLine("Process priority: {0}", Process.GetCurrentProcess().PriorityClass);

            Console.WriteLine("\n\rArrays:\t----------------------------------------------");

            bool b;
            b = bool_arr[1];
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                b = bool_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: bool\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                b = boolean_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: Boolean\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            int temp_int;
            temp_int = int_arr[1];
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                temp_int = int_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: Int\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            Int32 temp_int32 ;
            temp_int32 = int32_arr[1];
            watch.Reset();
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                temp_int32 = int32_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: Int32\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            Int64 temp_int64 ;
            temp_int64 = int64_arr[1];
            watch.Reset();
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                temp_int64 = int64_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: Int64\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            string s ;
            s = string_arr[1];
            watch.Reset();
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                s = string_arr[i];
            }
            watch.Stop();
            Console.WriteLine("Type: string\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            temp_int = intobject_arr[1].IntValue;
            watch.Reset();
            watch.Start();
            for (int i = 0; i < UPPER; i++)
            {
                temp_int = intobject_arr[i].IntValue;
            }
            watch.Stop();
            Console.WriteLine("Type: IntObject\tStructure: Array\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            Console.WriteLine("\n\rLists:\t----------------------------------------------");

            watch.Reset();
            watch.Start();
            foreach (var val in bool_list)
            {
                b = val;
            }
            watch.Stop();
            Console.WriteLine("Type: bool\tStructure: List\t\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            watch.Reset();
            watch.Start();
            foreach (var val in boolean_list)
            {
                b = val;
            }
            watch.Stop();
            Console.WriteLine("Type: Boolean\tStructure: List\t\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            temp_int = int_list.First();
            watch.Reset();
            watch.Start();
            foreach (var val in int_list)
            {
                temp_int = val;
            }
            watch.Stop();
            Console.WriteLine("Type: Int\tStructure: List\t\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            s = string_list.First();
            watch.Reset();
            watch.Start();
            foreach (var val in string_list)
            {
                s = val;
            }
            watch.Stop();
            Console.WriteLine("Type: string\tStructure: List\t\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            temp_int = intobject_list.First().IntValue;
            watch.Reset();
            watch.Start();
            foreach (var val in intobject_list)
            {
                temp_int = val.IntValue;
            }
            watch.Stop();
            Console.WriteLine("Type: IntObject\tStructure: List\t\tticks: {0}\tMiliSeconds:{1}", watch.ElapsedTicks, watch.ElapsedMilliseconds);

            Console.WriteLine();
            Console.WriteLine("Hit any key to exit.");
            Console.ReadKey();


        }
    }

    class IntObject
    {
        public int IntValue { get; set; }

        public IntObject ()
        {
            IntValue = 0;
        }

        public IntObject(int i)
        {
            IntValue = i;
        }
    }
}
于 2013-05-11T10:17:34.093 回答
-1

简单的答案对于引用类型是 YES,对于值类型是 NO

这是因为,.NET 泛型的实现方式是在使用值类型时避免装箱/拆箱,但不是在 ArrayLists 中。例如,aList<int>会将数组整数直接存储为堆上的整数而不是对象。然而,在引用类型的情况下,例如List<string>List<person>从对象到数据类型的转换/强制转换会有一点时间损失。

请参阅字符串和对象之间的比较HashSetList使用。

当您进行大量迭代List时,决定在、LinkedListDictionary、等之间使用哪一个主要是了解它们的存储方式以及它们的运行时复杂性。下面是一些 .NET 泛型的实现和渐近索引/迭代时间复杂度的列表:HashSet

.NET 泛型的内部实现/渐近时间复杂度


+------------------+------------------ ---------+-------------+--------------+
| | | 项目[i] | |
| 姓名 | 内部实现|------------+------------| 迭代 |
| | | 平均 案例 | 最坏情况 | |
+------------------+------------------ ---------+------------+------------+-------------+
| 列表 | 数组 | O(1) | O(1) | O(n) |
| 链表 | 双向链表 | O(n) | O(n) | O(n) |
| 字典 | 带有指向另一个数组的链接的哈希表 | O(1) | O(n) | O(n) |
| 哈希集 | 带有指向另一个数组的链接的哈希表 | O(1) | O(n) | O(n) |
| 排序字典 | 红黑树 | O(log n) | O(log n) | O(n) |
| 排序列表 | 数组 | O(1) | O(n) | O(n) |
| 排序集 | 红黑树 | O(n) | O(n) | O(n) |
+------------------+------------------ ---------+------------+------------+-------------+

总而言之,可以根据它们的时间复杂度确定迭代这些数据类型的最可能速度。就快速查找项目而言,List, SortedList, Dictionary, 并且HashSet总是优于其他项目,但是ListSortedList如果您要处理大量项目,那么不建议使用,这Dictionary对于HashSet大型列表具有优势(性能最重要的地方)。

参考:

  1. .NET 泛型集合的运行时复杂性
  2. List、HashSet和SortedSet对比分析
  3. 时间复杂度概述:字典类
  4. C# 中的泛型集合 - 时间复杂度概述
  5. 算法:大哦符号
  6. 排序字典(Tkey,Tvalue) - MSDN
  7. 列表(T) - MSDN

词汇表:

  1. 红黑树
  2. 装箱和拆箱
于 2013-05-12T10:11:47.983 回答