Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
25
Добавлен:
15.01.2021
Размер:
143.87 Кб
Скачать

12

Модуль 2.

Лекція 6. Стек і черга

6.1. Стек

6.1.1. Реалізація черги на мові C#. Класи Stack і Stack<T>

6.2. Черга

6.2.1. Реалізація черги на мові C#. Класи Queue і Queue<T>

6.1. Стек

Стек — окремий випадок однонаправленого лінійного списку з одним зв’язком, додавання елементів в який і вибірка з якого виконуються з одного кінця, який називається вершиною стека (головою – head). При вибірці елемент виключається із стека. Говорять, що стек реалізує принцип обслуговування LIFO (Last In — First Out, останнім прийшов, — першим пішов).

Рис. 6.1. Графічне зображення стеку

Властивості стеку:

  • елементи додаються у вершину (голову) стеку;

  • елементи видаляються з вершини (голови) стеку;

  • неможливо вилучити елемент із середини стеку, не вилучивши всі елементи, що йдуть попереду.

Для роботи зі стеком достатньо мати покажчик head на його вершину та допоміжний покажчик current на елемент стеку. Вершиною є останній доданий елемент стеку.

Стек повинен підтримувати наступні операції:

- додати (покласти) в кінець стека новий елемент

- витягнути із стека останній елемент

- отримати значення останнього елементу (не видаляючи його)

- отримати кількість елементів в стеку

- очистити стек (видалити з нього усі елементи)

6.1.1. Реалізація стеку на мові C#. Класи Stack і Stack<T>

У С# реалізацію стека представляють класи Stack і Stack<T>, який реалізує інтерфейси ICollection, IEnumerable і ICloneable. Це динамічні колекції, розмір яких змінюється.

Клас Stack<T> це універсальний двійник класу Stack.

Будемо розглядати колекції саме класу Stack<T>, який має кращу ефективність у порівнянні з класом Stack.

Конструктори класу Stack<T>

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

Таблиця 1. Конструктори

Stack<T>()

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

Stack<T> (IEnumerable<T>)

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

Stack<T>(Int32)

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

Окрім методів, визначених в інтерфейсах, що реалізуються класом Stack<T>, в цьому класі визначені власні методи.

Клас Stack<T> має одну властивість – Count, яка повертає чи встановлює кількість елементів у колекції.

Таблиця 2. Методи класу Stack<T>

Clear

Видаляє усі об'єкти з Stack<T>.

Contains

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

CopyTo

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

Equals(Object)

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

Finalize

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

GetEnumerator

Повертає нумератор для колекції Stack<T>.

GetHashCode

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

GetType

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

MemberwiseClone

Створює неповну копію поточного об'єкту Object. (Успадковано від Object.)

Peek

Повертає самий верхній об'єкт Stack<T>, але не видаляє його.

Pop

Видаляє і повертає об'єкт з верхньої частини Stack<T>.

Push

Вставляє об'єкт у верхню частину Stack<T>.

ToArray

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

ToString

Повертає рядок, що представляє поточний об'єкт. (Успадковано від Object.)

TrimExcess

Встановлює місткість рівною фактичній кількості елементів в Stack<T>, якщо ця кількість складає менше 90 відсотків поточної місткості

Розглянемо декілька прикладів використання стека.

Приклад 1. Для заданого значення n додамо в стек всі числа від 1 до n, а потім будемо вибирати їх із стека:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Stack_1

{

class Program

{

static void Main(string[] args)

{

Console.Write("n= ");

int n = int.Parse(Console.ReadLine());

Stack<int> intStack = new Stack<int>();

for (int i = 1; i <= n; i++)

intStack.Push(i);

Console.WriteLine("Розмірність стека " + intStack.Count);

Console.WriteLine("Верхній елемент стека = " + intStack.Peek());

Console.WriteLine("Розмірність стека " + intStack.Count);

Console.Write("Вміст стека = ");

while (intStack.Count != 0)

Console.Write("{0} ", intStack.Pop());

Console.WriteLine("\nНова розмірність стека " + intStack.Count);

Console.ReadKey();

}

}

}

Приклад 2.

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

У цьому прикладі коду створюється стек рядків з місткістю, що задається за замовчанням, а потім за допомогою методу Push в нього поміщаються п'ять рядків. Виконується перебір елементів стека, що не змінює його стану. Метод Pop використовується для видалення першого рядка із стека. Метод Peek використовується для перегляду наступного елементу в стеку, а потім метод Pop використовується для видалення цього елементу із стека.

Метод ToArray використовується для створення масиву і копіювання в нього елементів стека; потім цей масив передається конструктору Stack<T>, який приймає об'єкт типу IEnumerable<T>, створюючи копію стека з елементами, розміщеними в зворотному порядку. Відображуються елементи копії.

Створюється масив, розмір якого удвічі перевищує розмір стека, і за допомогою методу CopyTo виконується копіювання елементів масиву, починаючи з його середини. За допомогою конструктора Stack<T> створюється друга копія стека із зворотним порядком елементів, внаслідок чого три елементи null виявляються у кінці стека.

Метод Contains використовується для демонстрації того, що в першій копії стека міститься рядок "four", потім за допомогою методу Clear копія очищається, після чого звернення до властивості Count показує, що стек порожній.

using System;

using System.Collections.Generic;

class Example

{

public static void Main()

{

Stack<string> numbers = new Stack<string>();

numbers.Push("one");

numbers.Push("two");

numbers.Push("three");

numbers.Push("four");

numbers.Push("five");

foreach( string number in numbers )

{

Console.WriteLine(number);

}

Console.WriteLine("\nPopping '{0}'", numbers.Pop());

Console.WriteLine("Peek at next item to destack: {0}",

numbers.Peek());

Console.WriteLine("Popping '{0}'", numbers.Pop());

// Create a copy of the stack, using the ToArray method and the

// constructor that accepts an IEnumerable<T>.

Stack<string> stack2 = new Stack<string>(numbers.ToArray());

Console.WriteLine("\nContents of the first copy:");

foreach( string number in stack2 )

{

Console.WriteLine(number);

}

// Create an array twice the size of the stack and copy

// the elements of the stack, starting at the middle of

// the array.

string[] array2 = new string[numbers.Count * 2];

numbers.CopyTo(array2, numbers.Count);

// Create a second stack, using the constructor that

// accepts an IEnumerable(Of T).

Stack<string> stack3 = new Stack<string>(array2);

Console.WriteLine("\nContents of the second copy, with duplicates and nulls:");

foreach( string number in stack3 )

{

Console.WriteLine(number);

}

Console.WriteLine("\nstack2.Contains(\"four\") = {0}",

stack2.Contains("four"));

Console.WriteLine("\nstack2.Clear()");

stack2.Clear();

Console.WriteLine("\nstack2.Count = {0}", stack2.Count);

}

}

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

Приклад 3. У текстовому файлі міститься математичний вираз. Необхідно перевірити баланс круглих дужок у виразі.

у файлі skobki.txt знаходиться вираз:

(1+2)-4*(a-3)/(2-7+6)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace Stack_Skobki

{

class Program

{

static void Main(string[] args)

{

StreamReader fileIn = new StreamReader("skobki.txt");

string line = fileIn.ReadToEnd();

fileIn.Close();

Stack<int> skobki = new Stack<int>();

bool flag = true;

//перевіряємо баланс дужок

for (int i = 0; i < line.Length; i++)

{

//якщо поточний символ дужка, що відкривається, то поміщаємо її в стек

if (line[i] == '(') skobki.Push(i);

else if (line[i] == ')') //если поточний символ дужка, що закривається, то

{

//якщо стек порожній, то для закриваючої дужки не вистачає парної відкриваючої

if (skobki.Count == 0)

{ flag = false; Console.WriteLine("Можливо в позиції " + i + "зайва ) дужка"); }

else skobki.Pop(); //иначе витягуємо парну дужку

}

}

//якщо після перегляду рядка стек виявився порожнім, то дужки збалансовані

if (skobki.Count == 0) { if (flag) Console.WriteLine("дужки збалансовані"); }

else //инакше баланс дужок порушений

{

Console.Write("Можливо зайва ( дужка в позиції:");

while (skobki.Count != 0)

{

Console.Write("{0} ", (int)skobki.Pop());

}

Console.WriteLine();

}

}

}

}

6.2. Черга

Черга — це однозв'язний лінійний список, в якому елементи додаються в кінець списку, а видаляються з його початку.

Рис. 6.2. Графічне зображення черги

Властивості черги:

  • елементи додаються в кінець черги;

  • елементи зчитуються та видаляються з початку (вершини) черги;

  • неможливо отримати елемент із середини черги, не вилучивши всі елементи, що йдуть попереду.

6.2.1. Реалізація черги на мові C#. Класи Queue і Queue<T>

У С# реалізацію черги представляють: клас Queue і універсальний клас Queue<T>. Клас Queue як і стек реалізує інтерфейси ICollection, IEnumerable і ICloneable. Queue - це динамічна колекція, розмір якої змінюється. При необхідності збільшення місткості черги відбувається з коефіцієнтом зростання за замовчанням рівним 2.0.

Клас Queue <T> є універсальним двійником класу Queue.

Будемо розглядати роботу з універсальним класом Queue<T>. Черга реалізує інтерфейси:

IEnumerable<T>, ICollection, IEnumerable

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

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

Ім'я

Опис

Queue<T>()

створює новий порожній екземпляр Queue<T> з початковою місткістю за замовчанням (32)

Queue<T>(IEnumerable<T>)

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

Queue<T>(Int32)

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

Окрім методів, визначених в інтерфейсах, що реалізуються класом Queue<T>, в цьому класі визначені власні методи:

Клас Queue<T> має одну властивість – Count, яка повертає чи встановлює кількість елементів в колекції.

Таблиця 4. Методи класу Queue<T>

Ім'я

Опис

Clear

Видаляє усі об'єкти з Queue<T>.

Contains

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

CopyTo

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

Dequeue

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

Enqueue

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

Equals(Object)

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

Finalize

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

GetEnumerator

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

GetHashCode

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

GetType

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

MemberwiseClone

Створює неповну копію поточного об'єкту Object. (Успадковано від Object.)

Peek

Повертає об'єкт, що знаходиться на початку Queue<T>, але не видаляє його.

ToArray

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

ToString

Повертає рядок, що представляє поточний об'єкт. (Успадковано від Object.)

TrimExcess

Встановлює місткість рівною фактичній кількості елементів в Queue<T>, якщо ця кількість складає менше 90 відсотків поточної місткості.

Розглянемо декілька прикладів використання черги.