С# Array или Dictionary?

Я хотел знать, что массив С# имеет постоянную скорость доступа?
Мне нужно сохранить 1000 элементов в статическом массиве, которые будут инициализированы во время запуска сервера. Этот массив будет использоваться только для чтения, поэтому изменений в массиве не будет.
Должен ли я использовать простой массив С# (новый MyClass []) или словарь вместо этого.

Я действительно новичок в С# и пытаюсь понять, как работает доступ к массивам С#.
Могут ли они сравниваться с массивами С++ по скорости?

Ответ 1

Лучший выбор зависит от того, как вам нужно получить доступ к элементам.

Если вы хотите получить к ним доступ по индексу, используйте массив. Массивы в С# имеют постоянную скорость доступа и очень похожи на массив С++ с точки зрения скорости доступа.

Словари, однако, имеют очень быстрый доступ (свойство свойство приближается к времени доступа O (1), но зависит от того, насколько хороша реализация сохраненный ключ для GetHashCode). Если вам нужно искать ваши объекты на основе значения ключа, а не индекса, тогда словарь будет подходящим.

Ответ 2

Да, если вы знаете индекс, скорость является постоянной O (1), что очень похоже на поиск в словаре с поддержкой хэш-таблицы (например, Dictionary < > ).

Если индекс неизвестен, вам придется выполнить поиск (линейный, если элементы являются несортированными O (n) или двоичными, если они O (log n)).

Тем не менее, в реальном выражении поиск по массиву будет быстрее, потому что поиск в хэш-таблице - это две операции: вычислить хэш ключа для получения индекса и получить значение из внутреннего массива в этом индексе.

Также обратите внимание, что если хэш-код ключа плохо реализован, магические свойства хэш-таблицы быстро испаряются, а в худшем случае (где каждый ключ имеет один и тот же хэш-код) у вас будет сложный связанный список, в котором каждый поиск будет линейным поиском по стоимости O (n). Дважды проверьте эти хэш-коды!

Ответ 3

Это зависит от того, как вы собираетесь получать элементы из массива. Если вы собираетесь получать элементы по позициям (индексу) в массиве, тогда массив будет быстрее (или, по крайней мере, не медленнее, чем словарь). Если вы собираетесь искать элементы в массиве, чем словарь будет быстрее.

Ответ 4

Обновление последнего сообщения... теперь код включает класс для структуры данных списка. Я удалил некоторые ошибки из кода. Теперь он должен предоставить правильные результаты.

Кажется, что для одномерных структур данных структура списка может быть быстрее, чем массив. Но для двухмерных структур, как и в приведенном ниже коде, массивы значительно быстрее, чем списки, и значительно быстрее, чем словари.

Но все зависит от того, для чего вы хотите использовать структуры данных. Для относительно небольших наборов данных словари и списки часто более удобны для использования.

public interface IDataStructureTimeTestHandler
{
    void PerformTimeTestsForDataStructures();
}

public class DataStructureTimeTestHandler : IDataStructureTimeTestHandler
{
    // Example of use:
    //IDataStructureTimeTestHandler iDataStructureTimeTestHandler = new DataStructureTimeTestHandler();
    //iDataStructureTimeTestHandler.PerformTimeTestsForDataStructures();

    private IDataStructureTimeTest[] iDataStructureTimeTests;
    private TimeSpan[,] testsResults;

    public DataStructureTimeTestHandler()
    {
        iDataStructureTimeTests = new IDataStructureTimeTest[3];
        testsResults = new TimeSpan[4, 3];
    }

    public void PerformTimeTestsForDataStructures()
    {
        iDataStructureTimeTests[0] = new ArrayTimeTest();
        iDataStructureTimeTests[1] = new DictionaryTimeTest();
        iDataStructureTimeTests[2] = new ListTimeTest();
        for (int i = 0; i < iDataStructureTimeTests.Count(); i++)
        {
            testsResults[0, i] = iDataStructureTimeTests[i].InstantiationTime();
            testsResults[1, i] = iDataStructureTimeTests[i].WriteTime();
            testsResults[2, i] = iDataStructureTimeTests[i].ReadTime(LoopType.For);
            testsResults[3, i] = iDataStructureTimeTests[i].ReadTime(LoopType.Foreach);
        }
    }
}

public enum LoopType
{
    For,
    Foreach
}

public interface IDataStructureTimeTest
{
    TimeSpan InstantiationTime();
    TimeSpan WriteTime();
    TimeSpan ReadTime(LoopType loopType);
}

public abstract class DataStructureTimeTest
{
    protected IStopwatchType iStopwatchType;
    protected long numberOfElements;        
    protected int number;
    protected delegate void TimeTestDelegate();


    protected DataStructureTimeTest()
    {
        iStopwatchType = new StopwatchType();
        numberOfElements = 10000000;
    }

    protected void TimeTestDelegateMethod(TimeTestDelegate timeTestMethod)
    {
        iStopwatchType.StartTimeTest();
        timeTestMethod();
        iStopwatchType.EndTimeTest();
    }
}

public class ArrayTimeTest : DataStructureTimeTest, IDataStructureTimeTest
{
    private int[,] integerArray;


    public TimeSpan InstantiationTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(InstantiationTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void InstantiationTime_()
    {
        integerArray = new int[numberOfElements, 2];
    }

    public TimeSpan WriteTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(WriteTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void WriteTime_()
    {
        number = 0;
        for (int i = 0; i < numberOfElements; i++)
        {
            integerArray[i, 0] = number;
            integerArray[i, 1] = number;
            number++;
        }
    }

    public TimeSpan ReadTime(LoopType dataStructureLoopType)
    {
        switch (dataStructureLoopType)
        {
            case LoopType.For:
                ReadTimeFor();
                break;
            case LoopType.Foreach:
                ReadTimeForEach();
                break;
        }
        return iStopwatchType.TimeElapsed;
    }

    private void ReadTimeFor()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeFor_));
    }

    private void ReadTimeFor_()
    {
        for (int i = 0; i < numberOfElements; i++)
        {
            number = integerArray[i, 1];
        }
    }

    private void ReadTimeForEach()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeForEach_));
    }

    private void ReadTimeForEach_()
    {
        foreach (int i in integerArray)
        {
            number = i;
        }
    }
}

public class DictionaryTimeTest : DataStructureTimeTest, IDataStructureTimeTest
{
    private Dictionary<int, int> integerDictionary;


    public TimeSpan InstantiationTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(InstantiationTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void InstantiationTime_()
    {
        integerDictionary = new Dictionary<int, int>();
    }

    public TimeSpan WriteTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(WriteTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void WriteTime_()
    {
        number = 0;
        for (int i = 0; i < numberOfElements; i++)
        {
            integerDictionary.Add(number, number);
            number++;
        }
    }

    public TimeSpan ReadTime(LoopType dataStructureLoopType)
    {
        switch (dataStructureLoopType)
        {
            case LoopType.For:
                ReadTimeFor();
                break;
            case LoopType.Foreach:
                ReadTimeForEach();
                break;
        }
        return iStopwatchType.TimeElapsed;
    }

    private void ReadTimeFor()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeFor_));
    }

    private void ReadTimeFor_()
    {
        for (int i = 0; i < numberOfElements; i++)
        {
            number = integerDictionary[i];
        }
    }

    private void ReadTimeForEach()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeForEach_));
    }

    private void ReadTimeForEach_()
    {
        foreach (KeyValuePair<int, int> i in integerDictionary)
        {
            number = i.Key;
            number = i.Value;
        }
    }
}

public class ListTimeTest : DataStructureTimeTest, IDataStructureTimeTest
{
    private List<int[]> integerList;


    public TimeSpan InstantiationTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(InstantiationTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void InstantiationTime_()
    {
        integerList = new List<int[]>();
    }

    public TimeSpan WriteTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(WriteTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void WriteTime_()
    {
        number = 0;
        for (int i = 0; i < numberOfElements; i++)
        {
            integerList.Add(new int[2] { number, number });
            number++;
        }
    }

    public TimeSpan ReadTime(LoopType dataStructureLoopType)
    {
        switch (dataStructureLoopType)
        {
            case LoopType.For:
                ReadTimeFor();
                break;
            case LoopType.Foreach:
                ReadTimeForEach();
                break;
        }
        return iStopwatchType.TimeElapsed;
    }

    private void ReadTimeFor()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeFor_));
    }

    private void ReadTimeFor_()
    {
        for (int i = 0; i < numberOfElements; i++)
        {
            number = integerList[i].ElementAt(1);
        }
    }

    private void ReadTimeForEach()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeForEach_));
    }

    private void ReadTimeForEach_()
    {
        foreach (int[] i in integerList)
        {
            number = i.ElementAt(1);
        }
    }
}

Ответ 5

Доступ к массиву в С# - простая операция индекса, тогда как словарь - это поиск в хэш-таблице. Массивы сопоставимы с массивами С++, за исключением некоторых небольших накладных расходов на проверку границ, выполняемых языком.

Если вы не собираетесь менять содержимое, я бы использовал массив для размера данных, если ничего другого.

Ответ 6

Вот что я только что написал. Он может быть достаточно прост для разных структур данных. Он включает класс для каждой структуры данных (в настоящее время только массив и словарь).

Клиентский код - всего две строки:

IDataStructureTimeTestHandler iDataStructureTimeTestHandler = новый DataStructureTimeTestHandler(); iDataStructureTimeTestHandler.PerformTimeTestsForDataStructures();

Остальная часть кода:

public interface IStopwatchType
{
    TimeSpan TimeElapsed { get; }
    void StartTimeTest();
    void EndTimeTest();
}

public class StopwatchType : TailoredType, IStopwatchType
{
    private Stopwatch stopwatch;
    private TimeSpan timeElapsed;
    public TimeSpan TimeElapsed
    {
        get
        {
            return timeElapsed;
        }
    }

    public StopwatchType()
    {
    }

    public void StartTimeTest()
    {
        ClearGarbage();
        stopwatch = Stopwatch.StartNew();
    }

    public void EndTimeTest()
    {
        stopwatch.Stop();
        timeElapsed = stopwatch.Elapsed;
    }

    private void ClearGarbage()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();            
    }
}

public interface IDataStructureTimeTestHandler
{
    void PerformTimeTestsForDataStructures();
}

public class DataStructureTimeTestHandler : IDataStructureTimeTestHandler
{
    private IDataStructureTimeTest[] iDataStructureTimeTests;
    private TimeSpan[,] testsResults;


    public DataStructureTimeTestHandler()
    {
        iDataStructureTimeTests = new IDataStructureTimeTest[2];
        testsResults = new TimeSpan[4, 2];
    }

    public void PerformTimeTestsForDataStructures()
    {
        iDataStructureTimeTests[0] = new ArrayTimeTest();
        iDataStructureTimeTests[1] = new DictionaryTimeTest();
        for (int i = 0; i < iDataStructureTimeTests.Count(); i++)
        {
            testsResults[0, i] = iDataStructureTimeTests[0].InstantiationTime();
            testsResults[1, i] = iDataStructureTimeTests[0].WriteTime();
            testsResults[2, i] = iDataStructureTimeTests[0].ReadTime(LoopType.For);
            testsResults[3, i] = iDataStructureTimeTests[0].ReadTime(LoopType.Foreach);
        }
    }
}

public enum LoopType
{
    For,
    Foreach
}

public interface IDataStructureTimeTest
{
    TimeSpan InstantiationTime();
    TimeSpan WriteTime();
    TimeSpan ReadTime(LoopType loopType);
}

protected abstract class DataStructureTimeTest
{
    protected IStopwatchType iStopwatchType;
    protected long numberOfElements;        
    protected int number;
    protected delegate void TimeTestDelegate();


    protected DataStructureTimeTest()
    {
        iStopwatchType = new StopwatchType();
        numberOfElements = 100000;
    }

    protected void TimeTestDelegateMethod(TimeTestDelegate timeTestMethod)
    {
        iStopwatchType.StartTimeTest();
        timeTestMethod();
        iStopwatchType.EndTimeTest();
    }
}

public class ArrayTimeTest : DataStructureTimeTest, IDataStructureTimeTest
{
    private int[] integerArray;


    public TimeSpan InstantiationTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(InstantiationTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void InstantiationTime_()
    {
        integerArray = new int[numberOfElements];
    }

    public TimeSpan WriteTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(WriteTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void WriteTime_()
    {
        number = 0;
        for (int i = 0; i < numberOfElements; i++)
        {
            integerArray[i] = number;
            number++;
        }
    }

    public TimeSpan ReadTime(LoopType dataStructureLoopType)
    {
        switch (dataStructureLoopType)
        {
            case LoopType.For:
                ReadTimeFor();
                break;
            case LoopType.Foreach:
                ReadTimeForEach();
                break;
        }
        return iStopwatchType.TimeElapsed;
    }

    private void ReadTimeFor()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeFor_));
    }

    private void ReadTimeFor_()
    {
        for (int i = 0; i < numberOfElements; i++)
        {
            number = integerArray[i];
        }
    }

    private void ReadTimeForEach()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeForEach_));
    }

    private void ReadTimeForEach_()
    {
        foreach (int i in integerArray)
        {
            number = i;
        }
    }
}

public class DictionaryTimeTest : DataStructureTimeTest, IDataStructureTimeTest
{
    private Dictionary<int, int> integerDictionary;


    public TimeSpan InstantiationTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(InstantiationTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void InstantiationTime_()
    {
        integerDictionary = new Dictionary<int, int>();
    }

    public TimeSpan WriteTime()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(WriteTime_));
        return iStopwatchType.TimeElapsed;
    }

    private void WriteTime_()
    {
        number = 0;
        for (int i = 0; i < numberOfElements; i++)
        {
            integerDictionary.Add(number, number);
            number++;
        }
    }

    public TimeSpan ReadTime(LoopType dataStructureLoopType)
    {
        switch (dataStructureLoopType)
        {
            case LoopType.For:
                ReadTimeFor();
                break;
            case LoopType.Foreach:
                ReadTimeForEach();
                break;
        }
        return iStopwatchType.TimeElapsed;
    }

    private void ReadTimeFor()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeFor_));
    }

    private void ReadTimeFor_()
    {
        for (int i = 0; i < numberOfElements; i++)
        {
            number = integerDictionary[i];
        }
    }

    private void ReadTimeForEach()
    {
        TimeTestDelegateMethod(new TimeTestDelegate(ReadTimeForEach_));
    }

    private void ReadTimeForEach_()
    {
        foreach (KeyValuePair<int, int> i in integerDictionary)
        {
            number = i.Value;
        }
    }
}