Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритми та структури даних ЗПІ-91-20210115T104612Z-001 / Лекція 5. Спискові структури даних.doc
Скачиваний:
43
Добавлен:
15.01.2021
Размер:
450.56 Кб
Скачать

2. Колекції. Простір імен System.Collections

У С# під колекцією розуміється деяка група об'єктів. Класи-колекції спрощують реалізацію багатьох завдань програмування, пропонуючи вже готові рішення для побудови структур даних. Всі колекції розроблені на основі певних інтерфейсів, тому стандартизують спосіб обробки групи об'єктів. Середовище .NET Framework підтримує три основні типи колекцій: загального призначення, спеціалізовані і орієнтовані на побітову організацію даних.

У просторі імен System.Collections визначені набори стандартних колекцій і інтерфейсів, які реалізовані в цих колекціях.

Простір імен System.Collections.Specialized [спешелайз] включає спеціалізовані колекції, наприклад, колекцію рядків StringCollection і хеш-таблицю із строковими ключами StringDictionary.

У таблиці 1 перелічені основні колекції, визначені в просторі System.Collections та основні інтерфейси, які в них реалізовані.

Таблиця 1. Класи колекцій загального призначення (з простору імен System.Collections)

Клас

Призначення

Найважливіші з реалізованих інтерфейсів

ArrayList

Динамічний масив

IList, ICollection, IEnumerable, ICloneable

BitArray

Компактний масив для зберігання бітових значень

ICollection, IEnumerable, ICloneable

Hashtable

Хеш-таблиця

IDictionary, ICollection, IEnumerable, ICloneable

Queue

Черга

ICollection, ICloneable, IEnumerable

SortedList

Колекція, відсортована по ключах. Доступ до елементів — по ключу або по індексу

IDictionary, ICollection, IEnumerable, ICloneable

Stack

Стек

ICollection, IEnumerable

3. Універсальні колекції. Простір імен System.Collections.Generic

У другу версію бібліотеки .NET додані універсальні колекції для представлення цих структур даних. Ці колекції, розташовані у просторі імен System.Collections.Generic, дублюють аналогічні колекції простору імен System.Collections. Сьогодні рекомендується використовувати універсальні колекції скрізь, де потрібно замість звичайних колекцій, тому що вони працюють ефективніше (не потребують операцій упаковки, розпаковки даних).

У таблиці 2 наведено відповідність між звичайними і універсальними колекціями бібліотеки .NET.

Таблиця 2. Універсальні колекції System.Collections.Generic

Універсальний клас (версія 2.0)

Звичайний клас

Інтерфейси

Comparer<T>

Базовий клас для реалізацій універсального інтерфейсу IComparer<T>

Comparer

IComparer<T>.

List<T>

однозв’язний список

ArrayList

IList<T>, ICollection<T>,

IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,

IEnumerable

List<T>

BitArray

IList<T>, ICollection<T>,

IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,

IEnumerable

Dictionary<K,T>

словник

HashTable

Queue<T>

черга

Queue

LinkedList<T>

двозвязний список

Не має неуніверсального еквіваленту

SortedDictionary<K,T>

SortedList

Stack<T>

стек

Stack

Повний перелік класів простору імен System.Collections.Generic :

https://msdn.microsoft.com/ru-ru/library/system.collections.generic(v=vs.110).aspx

Таблиця 3. Універсальні інтерфейси

Інтерфейс

Опис

ICollection<T>

Визначає методи, використовувані для управління універсальними колекціями.

IComparer<T>

Визначає метод, що реалізується типом для порівняння двох об'єктів.

IDictionary<TKey, TValue>

Представляє універсальну колекцію пар ключ/значення.

IEnumerable<T>

Надає нумератор, який підтримує простий перебір елементів у вказаній колекції.

IEnumerator<T>

Підтримує простий перебір елементів універсальної колекції.

IEqualityComparer<T>

Визначає методи для підтримки операцій порівняння об'єктів відносно рівності.

IList<T>

Представляє колекцію об'єктів, доступ до яких можна дістати окремо, за індексом.

IReadOnlyCollection<T>

Представляє доступну тільки для читання колекцію елементів.

IReadOnlyDictionary<TKey, TValue>

Представляє універсальну колекцію пар "ключ-значення", доступну тільки для читання.

IReadOnlyList<T>

Представляє доступну тільки для читання колекцію об'єктів, доступ до яких можна дістати за індексом.

ISet<T>

Надає основний інтерфейс для абстракції наборів.

4. Універсальний клас List<>

Клас List<T> є універсальним еквівалентом класу ArrayList.

Реалізує універсальний інтерфейс IList<T> за допомогою масиву, розмір якого динамічно збільшується за потреби.

Таблиця 4. Конструктори класу List<T>

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

List<T>()

Створює новий порожній екземпляр класу List<T> з початковою ємністю за замовчанням.

List<T>(IEnumerable<T>)

Створює новий екземпляр List<T>, який містить елементи, скопійовані з вказаної колекції, і має місткість, достатню для розміщення усіх скопійованих елементів.

List<T>(Int32)

Створює новий порожній екземпляр класу List<T> з вказаною початковою ємністю .

Таблиця 5. Властивості класу List<T>

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

Властивість

Опис

Capacity

Повертає або задає загальне число елементів, які може вмістити внутрішня структура даних без зміни розміру.

Count

Отримує число елементів, що містяться в List<T>.

Item

Отримує або задає елемент з вказаним індексом.

Таблиця 6. Основні методи класу List<T>

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

Ім'я

Опис

Add

Додає об'єкт в кінець колекції List<T>.

AddRange

Додає елементи вказаної колекції в кінець списку List<T>.

BinarySearch(T)

Виконує пошук елементу за усім відсортованим списком List<T>, використовуючи порівняння за замовчанням, і повертає індекс елементу, відлічуваний від нуля.

BinarySearch(T, IComparer<T>)

Виконує пошук елементу за усім відсортованим списком List<T>, використовуючи вказаний компаратор, і повертає індекс елементу, відлічуваний від нуля.

BinarySearch(Int32, Int32, T, IComparer<T>)

Виконує пошук елементу в діапазоні елементів відсортованого списку List<T>, використовуючи вказаний метод порівняння, і повертає індекс елементу, відлічуваний від нуля.

Clear

Видаляє усі елементи з колекції List<T>.

Contains

Визначає, чи входить елемент до складу List<T>.

ConvertAll<TOutput>

Перетворює елементи поточного списку List<T> у інший тип і повертає список перетворених елементів.

CopyTo(T[])

Копіює увесь список List<T> у сумісний одновимірний масив, починаючи з першого елементу цільового масиву.

CopyTo(T[], Int32)

Копіює List<T> цілком в сумісний одновимірний масив, починаючи з вказаного індексу кінцевого масиву.

CopyTo(Int32, T[], Int32, Int32)

Копіює діапазон елементів із списку List<T> у сумісний одновимірний масив, починаючи з вказаного індексу кінцевого масиву.

Equals(Object)

Визначає, чи рівний заданий об'єкт поточному об'єкту. (Успадковано від Object.)

Exists

Визначає, чи містить List<T> елементи, що задовольняють умовам вказаного предиката.

Finalize

Дозволяє об'єкту спробувати звільнити ресурси і виконати інші операції очищення, перш ніж об'єкт утилізує в процесі зборки сміття. (Успадковано від Object.)

Find

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає перше знайдене входження в межах усього списку List<T>.

FindAll

Вибирає всі елементи, що задовольняють умовам вказаного предиката.

FindIndex(Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс першого знайденого входження в межах усього списку List<T>.

FindIndex(Int32, Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс першого входження в діапазоні елементів списку List<T>, починаючи із заданого індексу і закінчуючи останнім елементом.

FindIndex(Int32, Int32, Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс першого входження в діапазоні елементів списку List<T>, що починається із заданого індексу і містить вказане число елементів.

FindLast

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає останнє знайдене входження в межах усього списку List<T>.

FindLastIndex(Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс останнього знайденого входження в межах усього списку List<T>.

FindLastIndex(Int32, Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс останнього входження в діапазоні елементів списку List<T>, починаючи з першого елементу і закінчуючи елементом із заданим індексом.

FindLastIndex(Int32, Int32, Predicate<T>)

Виконує пошук елементу, вказаного предиката, що задовольняє умовам, і повертає відлічуваний від нуля індекс останнього входження в діапазоні елементів списку List<T>, що містить вказане число елементів і закінчується елементом із заданим індексом.

ForEach

Виконує вказану дію з кожним елементом списку List<T>.

GetEnumerator

Повертає нумератор, що здійснює перебір елементів списку List<T>.

GetHashCode

Грає роль хеш-функції для певного типу.(Успадковано від Object.)

GetRange

Створює неповну копію діапазону елементів початкового списку List<T>.

GetType

Повертає об'єкт Type для поточного екземпляра. (Успадковано від Object.)

IndexOf(T)

Здійснює пошук вказаного об'єкту і повертає відлічуваний від нуля індекс першого входження, знайденого в межах усього списку List<T>.

IndexOf(T, Int32)

Здійснює пошук вказаного об'єкту і повертає відлічуваний від нуля індекс першого входження в діапазоні елементів списку List<T>, починаючи із заданого індексу і до останнього елементу.

IndexOf(T, Int32, Int32)

Виконує пошук вказаного об'єкту і повертає відлічуваний від нуля індекс першого входження в діапазоні елементів списку List<T>, що починається із заданого індексу і містить вказане число елементів.

Insert

Додає елемент у список List<T> у позиції з вказаним індексом.

InsertRange

Вставляє елементи колекції в список List<T> у позиції з вказаним індексом.

Remove

Видаляє перше входження вказаного об'єкту з колекції List<T>.

RemoveAll

Видаляє усі елементи, що задовольняють умовам вказаного предиката.

RemoveAt

Видаляє елемент списку List<T> з вказаним індексом.

RemoveRange

Видаляє діапазон елементів із списку List<T>.

Reverse()

Змінює порядок елементів в усьому списку List<T> на зворотний.

Reverse(Int32, Int32)

Змінює порядок елементів у вказаному діапазоні.

Sort()

Сортує елементи в усьому списку List<T> за допомогою компаратора за замовчанням.

Sort(Comparison<T>)

Сортує елементи в усьому списку List<T> з використанням вказаного делегата System.Comparison<T>.

Sort(IComparer<T>)

Сортує елементи в усьому списку List<T> за допомогою вказаного компаратора.

ToArray

Копіює елементи списку List<T> у новий масив.

Приклад 1. https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

У наступному прикладі демонструється додавання, видалення і вставка простого бізнес-об'єкту в List<T>.

Для роботи зі списком потрібно реалізувати метод Equals, визначений в інтерфейсі IEquatable.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Lab

{

public class Part : IEquatable<Part>

{

public string PartName { get; set; }

public int PartId { get; set; }

public override string ToString()

{

return "ID: " + PartId + " Name: " + PartName;

}

public bool Equals(Part other)

{

if (other == null) return false;

return (this.PartId.Equals(other.PartId));

}

}

public class Example

{

public static void Main()

{

// Create a list of parts.

List<Part> parts = new List<Part>();

// Add parts to the list.

parts.Add(new Part() { PartName = "crank arm", PartId = 1234 });

parts.Add(new Part() { PartName = "chain ring", PartId = 1334 });

parts.Add(new Part() { PartName = "regular seat", PartId = 1434 });

parts.Add(new Part() { PartName = "banana seat", PartId = 1444 });

parts.Add(new Part() { PartName = "cassette", PartId = 1534 });

parts.Add(new Part() { PartName = "shift lever", PartId = 1634 }); ;

// Write out the parts in the list. This will call the overridden ToString method

// in the Part class.

foreach (Part aPart in parts)

{

Console.WriteLine(aPart);

}

// Check the list for part #1734. This calls the IEquitable.Equals method

// of the Part class, which checks the PartId for equality.

Console.WriteLine("\nContains(\"1734\"): {0}",

parts.Contains(new Part { PartId = 1734, PartName = "" }));

// Insert a new item at position 2.

Console.WriteLine("\nInsert(2, \"1834\")");

parts.Insert(2, new Part() { PartName = "brake lever", PartId = 1834 });

//Console.WriteLine();

foreach (Part aPart in parts)

{

Console.WriteLine(aPart);

}

Console.WriteLine("\nParts[3]: {0}", parts[3]);

Console.WriteLine("\nRemove(\"1534\")");

// This will remove part 1534 even though the PartName is different,

// because the Equals method only checks PartId for equality.

parts.Remove(new Part() { PartId = 1534, PartName = "cogs" });

Console.WriteLine();

foreach (Part aPart in parts)

{

Console.WriteLine(aPart);

}

Console.WriteLine("\nRemoveAt(3)");

// This will remove the part at index 3.

parts.RemoveAt(3);

Console.WriteLine();

foreach (Part aPart in parts)

{

Console.WriteLine(aPart);

}

Console.ReadKey();

}

}

}

Приклад 2. Використання класу List<> для зберігання колекції об'єктів класу Person, а також для зберігання цілих чисел.

using System;

using System.Collections.Generic;

using System.Collections;

using System.Linq;

using System.Text;

namespace Lab

{

public class Person

{

public string Name; //имя

public int Age; // возраст

public string Role; // роль

public string GetName() { return Name; }

public int GetAge() { return Age; }

public Person(string N, int A)

{

this.Name = N;

this.Age = A;

}

public void Passport()

{

Console.WriteLine("Name = {0} Age = {1}", Name, Age);

}

}

class Program

{

static void Main(string[] args)

{

List<Person> pers = new List<Person>();

pers.Add(new Person("Іванов",18));

pers.Add(new Person("Петров",20));

pers.Add(new Person("Морозов", 3));

foreach (Person x in pers) x.Passport();

List<int> lint = new List<int>();

lint.Add(5); lint.Add(1); lint.Add(3);

lint.Sort();

int а = lint[2];

Console.WriteLine(а);

foreach (int x in lint) Console.Write(x + " ");

Console.ReadLine();

}

}

}

У цьому прикладі створюється дві колекції. Перша (pers) містить елементи класу Person.

Колекція lint складається з цілих чисел, причому для роботи з ними не потрібні явні перетворення типу при отриманні елементу з колекції.

Приклад 3.

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

У наступному прикладі показано декілька властивостей і методів універсального класу List<T> строкового типу. За допомогою конструктора за замовчанням створюється список рядків з місткістю за замовчанням. Виводиться значення властивості Capacity, а потім за допомогою методу Add додається декілька елементів. Виводиться список цих елементів, а потім знову виводиться значення властивості Capacity і разом з ним - значення властивості Count, що показує, що місткість збільшується в міру необхідності.

За допомогою методу Contains перевіряється наявність деякого елементу в списку, за допомогою методу Insert в середину списку вставляється новий елемент, після чого знову виводиться вміст списку.

За допомогою властивості за замовчанням Item (індексатор в C#) із списку вибирається елемент, за допомогою методу Remove видаляється перший екземпляр дубльованого елементу, доданий раніше, і вміст списку виводиться знову. Метод Remove завжди видаляє перший виявлений ним екземпляр.

За допомогою методу TrimExcess місткість зменшується відповідно до числа елементів, і виводяться значення властивостей Capacity і Count. Якщо не задіяна місткість складає менше 10% від загальної місткості, змінювати розмір списку не потрібно.

В кінці використовується метод Clear для видалення усіх елементів із списку, і виводяться значення властивостей Capacity і Count.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Lab

{

public class Example

{

public static void Main()

{

List<string> dinosaurs = new List<string>();

Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);

dinosaurs.Add("Tyrannosaurus");

dinosaurs.Add("Amargasaurus");

dinosaurs.Add("Mamenchisaurus");

dinosaurs.Add("Deinonychus");

dinosaurs.Add("Compsognathus");

Console.WriteLine();

foreach (string dinosaur in dinosaurs)

{

Console.WriteLine(dinosaur);

}

Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);

Console.WriteLine("Count: {0}", dinosaurs.Count);

Console.WriteLine("\nContains(\"Deinonychus\"): {0}",

dinosaurs.Contains("Deinonychus"));

Console.WriteLine("\nInsert(2, \"Compsognathus\")");

dinosaurs.Insert(2, "Compsognathus");

Console.WriteLine();

foreach (string dinosaur in dinosaurs)

{

Console.WriteLine(dinosaur);

}

// Shows accessing the list using the Item property.

Console.WriteLine("\ndinosaurs[3]: {0}", dinosaurs[3]);

Console.WriteLine("\nRemove(\"Compsognathus\")");

dinosaurs.Remove("Compsognathus");

Console.WriteLine();

foreach (string dinosaur in dinosaurs)

{

Console.WriteLine(dinosaur);

}

dinosaurs.TrimExcess();

Console.WriteLine("\nTrimExcess()");

Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);

Console.WriteLine("Count: {0}", dinosaurs.Count);

dinosaurs.Clear();

Console.WriteLine("\nClear()");

Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);

Console.WriteLine("Count: {0}", dinosaurs.Count);

Console.ReadKey();

}

}

}

5. Пошук заданого елементу у списку List<>

Метод Contains визначає, чи входить елемент у список List<>. У прикладі 1 вище, цей метод використовується для пошуку елемента PartId

// Check the list for part #1734. This calls the IEquitable.Equals method

// of the Part class, which checks the PartId for equality.

Console.WriteLine("\nContains(\"1734\"): {0}",

parts.Contains(new Part { PartId = 1734, PartName = "" }));

Для виконання порівняння на рівність складних об’єктів потрібно зробити клас нащадком інтерфейсу IEquatable <> і реалізувати методи інтерфейсу.

public class Part : IEquatable<Part>

Приклад 4. (модифікований до msdn)

https://msdn.microsoft.com/ru-ru/library/bhkz42b3(v=vs.110).aspx

У наступному прикладі міститься список складних об'єктів типу Box. Клас Box реалізує метод IEquatable<T>.Equals, так, щоб два поля вважалися рівними, якщо їх розміри рівні. В даному прикладі метод Contains повертає значення true, оскільки поле, що має задані виміри, вже знаходиться в колекції.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Lab

{

class Program

{

static void Main(string[] args)

{

List<Box> boxes = new List<Box>();

boxes.Add(new Box(8, 8, 4));

boxes.Add(new Box(8, 4, 8));

boxes.Add(new Box(8, 6, 4));

if (boxes.Contains(new Box(8, 1, 4)))

{

Console.WriteLine("An equal box is already in the collection.");

}

else

{

Console.WriteLine("Box can be added.");

boxes.Add(new Box(8, 1, 4));

}

//Outputs "An equal box is already in the collection."

Console.ReadKey();

}

}

public class Box : IEquatable<Box>

{

public Box(int h, int l, int w)

{

this.Height = h;

this.Length = l;

this.Width = w;

}

public int Height { get; set; }

public int Length { get; set; }

public int Width { get; set; }

public bool Equals(Box other)

{

if (this.Height == other.Height && this.Length == other.Length

&& this.Width == other.Width)

{

return true;

}

else

{

return false;

}

}

}

}