1 СТРУКТУРЫ ДАННЫХ C#. В C#.NET есть много различных структур данных, например Array - одна из самых часто используемых. Однако C# поставляется с гораздо большим количеством таких структур. Необходимо выбирать правильные структуры данных для написания хорошо структурированных и эффективных программ. В этой статье я перечислю встроенные в C# структуры данных, включая новые из C#.Net 3.5. 1.1 Array. Возможно самым простой и известной структурой данных является array. В C# array является простым массивом объектов. Для него характерно то, что все его объекты одного типа и их количество фиксировано. Он объявляется и инициализируется следующим образом: 1 [object type][] myArray = new [object type][number of elements] Некоторые примеры: 1 2 int[] myIntArray = new int[5]; int[] myIntArray2 = { 0, 1, 2, 3, 4 }; Как можно видеть из приведенного выше примера, массив может инициализироваться пустым или с уже заданными элементами. 1.2 ArrayList. ArrayList - это динамический массив. Он может иметь любое количество объектов любого типа. Ниже приведён пример, где ArrayList - массив произвольных объектов, расширяющийся по мере добавления в него новых элементов. 1 2 3 4 ArrayList myArrayList = new ArrayList(); myArrayList.Add(56); myArrayList.Add("String"); myArrayList.Add(new Form()); Недостатком ArrayList является необходимость распаковки его элементов в их оригинальный тип: 1 int arrayListValue = (int)myArrayList[0]; 1.3 List<> (список). Вкратце, структура данных List<> - это строго типизированный ArrayList. Это тоже динамический массив, но его отличие от ArrayList в том, что List<> должен содержать данные только одного типа: 1 2 3 4 List<int> intList = new List<int>(); intList.Add(45); intList.Add(34); </int></int> Поскольку элементы List<> относятся к одному типу их нет необходимости распаковывать при получении: 1 int listValue = intList[0]; Для простых типов данных (int, bool, итд.) использование List<> обеспечивает гораздо большую скорость работы, нежели использование ArrayList. 1.4 LinkedList<> (двусвязный список). Теперь совершенно другой тип структуры данных - LinkedList<>. LinkedList<> - это группа объектов, которые вместо того, чтобы индексироваться по ссылке (как, например, Array), расположены в узлах и соединены друг с другом. LinkedList<> узел содержит три основных значения: сам объект, ссылку на следующий узел, а также ссылки на предыдущий узел. Какой смысл в такой структуре данных? Её преимущество в том, что добавление элемента в середину списка происходит значительно быстрее, чем в другом типе структуры данных. LinkedList<> также снижает затраты памяти до минимума. С другой стороны, для нахождения элемента, находящегося в середине или в конце списка, требуется довольно много времени. 1 2 3 LinkedList<int> list = newLinkedList<int>(); list.AddLast(6); </int></int> Получение значения производится не напрямую, а перебором: 1 list.First.Value 1 list.Last.Value или Теперь мы можем перейти к более сложным структурам данных. 1.5 Dictionary<> (словарь). Структура данных Dictionary<> очень удобна, она позволяет программисту обращаться к значению по её ключевому индексу. Что это значит? ArrayList, к примеру, автоматически создаёт свои "ключи" - числа, 1, 2 и т.д., так, что для доступа к необходимому объекту используется следующая запись: 1 myArrayList[2]; Dictionary<> позволяет использовать ключи любого типа, например: 1 2 3 4 Dictionary<string, int=""> myDictionary = new Dictionary<string, int="">(); myDictionary.Add("one", 1); myDictionary.Add("twenty", 20); </string,></string,> Получение значения производится следующим образом: 1 int myInt = myDictionary["one"]; При использовании Dictionary<> нет необходимости метаться между типами. Также никто не запрещает создать Dictionary<> таким образом: 1 2 Dictionary<int, int="" dictionary<string,="">> nestedDictionary = new Dictionary<int, int="" dictionary<string,="">>(); 3 </int,></int,> То есть вложенные структуры данных Dictionary<> возможны и разрешены. Я понимаю, что может ввести в заблуждение то, как получить все значения из этой структуры данных, поскольку мы можем не знать закономерности в составлении её ключей. К счастью, это не обязательно, вот пример получения всех данных из Dictionary<>: 1 2 3 4 5 6 7 //List<[same type as index]> List<string> keyList = new List<string> (myDictionary.Keys); for (int i = 0; i < keyList.Count; i++) { int myInt = myDictionary[keyList[i]]; } </string></string> Если вы заинтересованы, вы можете прочитать более подробно о C# Dictionary<>. 1.6 Hashtable (хеш-таблица). Структура данных Hashtable очень похожа на структуру Dictionary<>. Hashtable также принимает пару ключ/значение, но они должны быть объектными ссылками ссылкой на ключ и ссылкой на сам объект. С приходом .NET 2.0 обобщённые словари вроде Dictionary<> стали более предпочтительнее, по сравнению со словарями, основанными на типе Object. Значения в хеш-таблице хранится в порядке, зависящем от хэш-кода их ключа. 1 Hashtable myTable = new Hashtable(); 1.7 HashSet<>. Структура данных HashSet<> была введена в C# Net 3.5. Эта специфическая структура данных очень сильно напоминает List<>. В чём же различие? У HashSet<> есть очень важная особенность - она не допускает повторяющихся значений. Например: 1 2 3 4 5 6 7 8 9 HashSet<int> mySet = new HashSet<int>(); mySet.Add(3); mySet.Add(5); mySet.Add(3); mySet.Add(10); List<int> myListFromSet = mySet.ToList<int>(); int myInt = myListFromSet[2]; </int></int></int></int> Если mySet был бы обычной структурой данных List<>, то индекс 2 должен был вернуть значение 3 (проверьте сами). Но если вы запустите пример, вы увидите, что myInt возвращает значение 10. Это происходит потому, что HashSet<> игнорирует дубликат со значением 3. Для более подробного изучения вы можете посетить страницу C# HashSet<>. 1.8 Stack и Stack<>(стек). Класс Stack является одним из многих структур данных в C#, которые напоминают ArrayList. Как и ArrayList, стек имеет методы для добавления и получения данных, но с небольшой разницей в их поведении. Чтобы добавить в стек данные, необходимо использовать метод Push, который является эквивалентом Add в ArrayList. Получение значения немного отличается. Стек имеет метод Pop, который возвращает и одновременно удаляет последний добавленный объект. Если вы хотите получить последнее значение в стеке без его удаления, используйте метод Peek. Стек работает по алгоритму LIFO, что расшифровывается как Last-In-First-Out (последним пришёл - первым обслужен). Эта специфическая структура данных будет полезна, если вам необходимо вернуться той же дорогой, так сказать. Есть два вида объявления стека в C#: 1 2 3 Stack stack = new Stack(); Stack<string> stack = new Stack<string>(); </string></string> Различия в них в том, что первая структура данных будет работать с производными от класса Object, тогда как вторая принимает только определённый тип данных. Вот код C#, для добавления и извлечения данных из стека: 01 02 03 04 05 06 07 08 09 10 Stack<string> stack = new Stack<string>(); stack.Push("1"); stack.Push("2"); stack.Push("3"); while (stack.Count > 0) { MessageBox.Show(stack.Pop()); } </string></string> Если запустить этот код, то увидите, что список возвращён в следующем порядке: 3, 2, 1. 1.9 Queue и Queue<>(очередь). Очередь - ещё одна из многих структур данных в C#. Очередь очень похожа на стек, но есть одно важное отличие. Вместо того, чтобы следовать алгоритму LIFO, очередь следует алгоритму FIFO, что расшифровывается как First-In-First-Out (первый пришёл - первый обслужен). К примеру, когда вы отправляете статью для утверждения на сайт, то там она добавляется в очередь на утверждение. Таким образом, объекты, добавленные первыми, первыми будут и обработаны. Добавление элемента в очередь (аналогичено Push для стека) осуществляется методом Enqueue: 1 queue.Enqueue("1"); Извлечение элемента - методом Dequeue: 1 queue.Dequeue(); Аналогично, метод Peek позволяет просмотреть верхнее значение в очереди, не удаляя его. Эта специфическая структура данных очень часто используется в связке со стеком. Вот простой код для добавления и извлечения данных из очереди: 01 02 03 04 05 06 07 08 09 10 Queue<string> queue = new Queue<string>(); queue.Enqueue("1"); queue.Enqueue("2"); queue.Enqueue("3"); while (queue.Count > 0) { MessageBox.Show(queue.Dequeue()); } </string></string> Также имейте ввиду, что очередь, как и стек, может быть определена как любого типа данных (Queue), так и только для одного типа (Queue<>).