Продолжение темы 4. Понятие классов и методов (функции) языка C#.

advertisement
Продолжение темы 4. Понятие классов и методов (функции) языка C#.
Организация данных в виде строк.
Лекция 21 СТЕКИ
21.1 Понятие списочных структур
Работа с любой информационной, справочной системой требует
обращение к некоторым массивам данных. Обычно данные хранятся в виде
файлов на магнитных дисках. Однако если к данным файла необходимо
непрерывно обращаться и выполнять в них различные поисковые операции,
то желательно размещать эти файлы данных в памяти компьютера, так как
время поиска данных в файле на магнитном диске в тысячи раз больше
времени поиска данных в файле памяти компьютера.
Возникает задача по размещению в памяти компьютера больших файлов
справочной информации.
Существует множество алгоритмов размещения в памяти компьютера
данных из файла на магнитном диске. Например, файлы данных можно
представлять в виде различных таблиц, матриц. Табличная форма
представления информации предполагает использование традиционных
алгоритмов обработки данных в массивах.
Одним из вариантов размещения данных в памяти компьютера являются
различные списочные структуры. Организация списка записей в памяти
компьютера предполагает, что в структуру каждого элемента списка (записи)
включается дополнительное поле – указатель на следующий элемент списка
(обычно это поле называют next), которое позволяет «связывать» элементы
списка в единое целое. Такая структура обязательно должна иметь точку
входа в список – заголовок или начало списка и признак окончания списка
(значение поля next последнего элемента списка равно NULL) или, что
переменная, определяющая количество элементов списка равна нулю.
…
zagolovok
Зп 1
Зп 2
Зп 3
Зп N
next
next
next
next
NULL
Рисунок 21.1 – Структура простого списка
Минимальный набор действий (алгоритмов), которые обычно
выполняются со списочными структурами, включает следующий перечень:
– создание списка из файла записей;
– просмотр списка;
– добавление нового элемента в список (в начало, середину и конец
списка);
– удаление элемента из списка (из начала, середины и конца списка);
– запись списка в файл;
– объединение нескольких списков в один;
– деление одного списка на два или несколько независимых списков;
– сортировка элементов списка и т.д.
По способу добавления и удаления элемента из простого списка все
списочные структуры можно разделить на четыре группы:
– стеки;
– очереди;
– деки;
– простые списки.
Стек – простой список, в котором добавление и удаление элемента
осуществляется в одном конце списка. Часто принцип работы стека поясняют
фразой «Вошедший первым выходит последним, а вошедший последним
выходит первым».
Очередь – простой список, в котором добавление элемента
осуществляется в одном конце списка (конец очереди), а удаление или
обслуживание элемента в другом конце списка (начало очереди).
Дек – простой список, в котором добавление и удаление элемента может
осуществляться в любом конце списка.
В простом списке добавление и удаление элемента может
осуществляться в любом месте списка, в том числе и в середину списка.
21.2 Основные характеристики структурой типа стек
Структура типа стек широко используется в различных вычислительных
процессах. Процессор компьютера использует стек при обработке
прерываний. Многие алгоритмы используют стеки для реализации
«возвращения» алгоритма к предыдущему состоянию, например, при
прохождении лабиринта или «обходе» дерева или графа. Алгоритмы
решения многих транспортных задач используют стек для нахождения
оптимальных маршрутов и т.д.
Естественно,
в
дисциплине
«Алгоритмизация
и
основы
программирования», мы не можем обойти стороной такую нужную для
алгоритмизации структуру как стек, тем более что в языке C# ей выделен
специальный класс (Stack) с набором методов.
Основными алгоритмы при работе со стеком являются алгоритмы
добавления элемента в стек, исключения элемента из стека и просмотра
содержимого стека.
Доступ в структуру типа стек возможен только в одном его конце,
который обычно называют вершиной стека.
Класс стек представляет собой динамическую коллекцию – объединение
однотипных данных. При расширении стека (во время добавления элемента в
«заполненный» стек) емкость стека динамически удваивается.
В классе Stack определены следующие три конструктор:
Public Stack();
Public Stack(int capacity);
Public Stack(ICollection n);
Первый конструктор создает «пустой» стек на 10 элементов. Второй
конструктор создает «пустой» стек с начальной емкостью на capacity
элементов. Третий конструктор создает стек на n элементов, который
инициируется элементами ICollection.
21.3 Организация работ со структурой типа стек
Основные методы класса Stack представлены в таблице 21.1.
Таблица 21.1 Основные методы класса Stack.
Меод
Описание
public virtual bool Возвращает значение true, если объект v содержится в
Contains(object v) стеке, иначе false
public virtual void Очищает стек (свойство Count – число элементов стека
устанавливается в нуль).
Clear()
Возвращает элемент вершины стека, но не удаляет его
public virtual
object Peek()
Возвращает элемент вершины стека и удаляет его
public virtual
object Pop()
public virtual void Добавляет элемент v в стек – в вершину стека
Push(object v)
Для просмотра содержимого стека часто используется операция in –
определение принадлежности, например:
Console.Write(" Содержимое стека = ");
foreach (int i in vst)
Console.Write(i + " ");
Console.WriteLine();
Приведенные строки кода позволяют просмотреть стек состоящий из
целых чисел и вершиной vst.
В качестве примера использования алгоритмов работы со стеком
рассмотрим решение следующей задачи:
Задача 21.1 Для стека на 5 целых чисел случайным образом формируется
вероятность включения и исключения числа. При этом вероятность
включения числа в стек равна 70%, а исключения 30%. Числа так же
формируются случайным образом и находятся в диапазоне минус 50 до 50.
При заполнении стека и попытке добавить новое число в стек
происходит «переключение» вероятностей включения и исключения на
противоположные значения. Окончание работы программы определяется
попыткой исключить число из «пустого» стека.
Исходный код программы имеет следующий вид:
using System;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void vkl(Stack vst, int n)
{
vst.Push(n);
Console.Write("В стек помещен элемент {0}", n);
Console.Write(" Содержимое стека = ");
foreach (int i in vst)
Console.Write(i + " ");
Console.WriteLine();
}
static void iskl(Stack vst)
{
if (vst == null) Console.WriteLine("Стек пуст !");
else
{
int n = (int) vst.Pop();
Console.Write("Из стека удален элемент {0}", n);
Console.Write(" Содержимое стека = ");
foreach (int i in vst)
Console.Write(i + " ");
Console.WriteLine();
}}
static void Main()
{
Stack vstek = new Stack();
int i, k, n;
Random rnd = new Random();
i=0;
while (i < 5)
{
k = rnd.Next() % 101;
if (k <= 70)
{
i++;
n = rnd.Next() % 101 - 50;
vkl(vstek, n);
}
else
if (i > 0)
{
i--;
iskl(vstek);
}
}
Console.WriteLine(" Стек переполнен !");
while (i > 0)
{
k = rnd.Next() % 101;
if (k <= 30)
{
i++;
n = rnd.Next() % 101 - 50;
vkl(vstek, n);
}
else
if (i > 0)
{
i--;
iskl(vstek);
}
}
Console.WriteLine(" Стек пуст !");
Console.WriteLine("Для продолжения нажмите клавишу
Enter");
Console.ReadLine();
}
}
}
Работа программы:
В стек помещен элемент 24 Содержимое стека = 24
Из стека удален элемент 24 Содержимое стека =
В стек помещен элемент -31 Содержимое стека = -31
Из стека удален элемент -31 Содержимое стека =
В стек помещен элемент -35 Содержимое стека = -35
В стек помещен элемент -1 Содержимое стека = -1 -35
В стек помещен элемент -1 Содержимое стека = -1 -1 -35
Из стека удален элемент -1 Содержимое стека = -1 -35
В стек помещен элемент 9 Содержимое стека = 9 -1 -35
В стек помещен элемент 11 Содержимое стека = 11 9 -1 -35
В стек помещен элемент 29 Содержимое стека = 29 11 9 -1 -35
Стек переполнен !
Из стека удален элемент 29 Содержимое стека = 11 9 -1 -35
Из стека удален элемент 11 Содержимое стека = 9 -1 -35
Из стека удален элемент 9 Содержимое стека = -1 -35
Из стека удален элемент -1 Содержимое стека = -35
В стек помещен элемент -41 Содержимое стека = -41 -35
В стек помещен элемент 7 Содержимое стека = 7 -41 -35
Из стека удален элемент 7 Содержимое стека = -41 -35
В стек помещен элемент -30 Содержимое стека = -30 -41 -35
В стек помещен элемент -28 Содержимое стека = -28 -30 -41 -35
Из стека удален элемент -28 Содержимое стека = -30 -41 -35
Из стека удален элемент -30 Содержимое стека = -41 -35
Из стека удален элемент -41 Содержимое стека = -35
Из стека удален элемент -35 Содержимое стека =
Стек пуст !
Для продолжения нажмите клавишу Enter
В программу включены комментарии каждой операции включения и
исключения элемента из стека.
21.4 Вопросы для проверки
21.4.1 Как называется простой список, в котором все включения и
исключения элементов выполняются в одном конце списка?
21.4.2 Как называется начало стека?
21.4.3 Что означает запись Public Stack(ICollection n);?
21.4.4 Что делает следующий фрагмент программы
int n = (int) vst.Pop();,
где vst – вершина стека?
21.4.5 Что делает следующий фрагмент программы:
i = 0;
while (i < 5)
{
i++;
n = rnd.Next() % 101 - 50;
vstek.Push(n);
},
где vstek – вершина стека?
Продолжение темы 4. Понятие классов и методов (функции) языка C#.
Организация данных в виде строк.
Лекция 22 ОЧЕРЕДИ, СПИСКИ
22.1 Организация работ со структурой типа очередь
Структуры типа очередь широко используется в алгоритмах «поиска с
возвращением». Алгоритмы обход всех вершин графов, деревьев используют
либо стеки – при реализации алгоритма «обхода в глубину», либо очереди –
при реализации алгоритма «обхода в ширину». Многие задачи теории
массового обслуживания используют очереди для нахождения оптимальных
вариантов решения и т.д.
Структуры типа очередь может иметь два заголовка – начала очереди, с
помощью которого осуществляется обслуживание элемента очереди
(удаление элемента) и конца очереди, который используется для постановки
новых элементов в очередь на обслуживание (включение элемента).
Так же как и для структуры типа стек в языке C# ей выделен
специальный класс (Queue) для работы с очередями. Этот класс снабжен
данными и набором методов.
В классе Queue определены следующие три конструктор:
Public Queue ();
Public Queue (int capacity);
Public Queue (ICollection c);
Первый конструктор создает «пустой» стек на 10 элементов. Второй
конструктор создает «пустой» стек с начальной емкостью на capacity
элементов. Третий конструктор создает стек на n элементов, который
инициируется элементами ICollection.
Основные методы класса Queue представлены в таблице 22.1.
Таблица 22.1 Основные методы класса Queue
Метод
Описание
public virtual bool Возвращает значение true, если объект v содержится в
Contains(object v) очереди, иначе false
public virtual void Очищает очередь (свойство Count – число элементов
очереди устанавливается в нуль).
Clear()
public virtual
Возвращает объект из начала очереди, но не удаляет его
object Peek()
public virtual
Возвращает объект из начала очереди и удаляет его
object Dequeue()
public virtual void Добавляет объект v в конец очереди
Enqueue(object v)
В качестве примера, поясняющего работу методов очереди, рассмотрим
решение следующей задачи.
Задача 22.1 Магазин за 1 день посещает 250 человек. Обслуживание
покупателей предполагает продажу им : хлеба – вероятность 25%; сыра –
вероятность 20%; печенья – вероятность 20%; пиво – вероятность 10% и
мороженного – вероятность 25%. Считаем, что каждый покупатель
приобретает только один продукт. Все события равновероятны на диапазоне
чисел от 0 – 100. Организовать очередь покупателей, а при ее обслуживании
определить и напечатать: количество проданных продуктов каждого вида, и
какой продукт покупается чаще.
Из условия задачи известно, что все события равновероятны,
следовательно, если формировать случайные числа от 0 до 100, то
вероятность свершения события можно определять попаданием числа в
заданный диапазон. Например, вероятность покупки хлеба можно определить
диапазоном от 1 до 25, сыра – от 26 до 45, печенья – от 46 до 65, пива – от 66
до 75 и мороженного – от 76 до 100.
Каждый вид продукта можно представить целым числом от 0 до 4.
Таким образом, можно очередь покупателей заменить очередью покупаемых
ими продуктов, которые представлены целыми числами.
С учетом предложенных допущений программный код имеет
следующий вид:
using
using
using
using
System;
System.Collections;
System.Linq;
System.Text;
namespace ConsoleApplication1
{
class Program
{
public static int n;
static void vkl(Queue ocer, int n)
{
ocer.Enqueue(n);
}
static void iskl(Queue ocer)
{
n = (int)ocer.Dequeue();
}
public static void Main()
{
Queue zagol = new Queue();
int[] masi = new int[5];
char[] masc = new char[5] {'Х', 'С','П','Н','М'};
string[] mass = new string[5]
{"Хлеб","Сыр","Печенье","Напиток пиво","Мороженное"};
int i, j, p, k;
Random rnd = new Random();
for (i = 0; i < 4; i++) masi[i] = 0;
for (i = 0; i < 250; i++)
{
p = rnd.Next() % 100 + 1;
if (p <= 25) vkl(zagol, 0);
if
if
if
if
(25 < p && p <= 45) vkl(zagol, 1);
(45 < p && p <= 65) vkl(zagol, 2);
(65 < p && p <= 75) vkl(zagol, 3);
(p > 75) vkl(zagol, 4);
};
for (i = 0; i < 250; i++)
{
iskl(zagol);
masi[n]++;
Console.Write(masc[n]);
if ((i+1)%25==0) Console.WriteLine();
};
k = 0; j = 0;
for (i = 0; i < 5; i++)
{
Console.WriteLine(" {0} = {1}", mass[i], masi[i]);
if (k < masi[i]) { k = masi[i]; j = i; }
}
Console.WriteLine("Больше всего продано {0} = {1}",
mass[j], masi[j]);
Console.WriteLine("Для продолжения нажмите клавишу
Enter");
Console.ReadLine();
}
}
}
Работа программы:
МНХСМХСХПССНХМХМССХСММХММ
ННСПМХМХМПССНПМСМСПСМХМХП
ХССМСППСПММПХПММХХМНППНСП
СМХХСНМХХММХНПСМХХМСММНММ
ХМПММПНММСНМПНПХССХПНСНММ
ПМСПНСХССХМНПХХПСМПМСМПМС
СХММХМПМХСХММПМСНСХПМХХММ
ПХПХПХППХХМНСПМММПМПММНХС
НХМХМНСПМНСХХХПХННСПННХСС
ХХХСПХСМХСПППМХСНПММНХХМП
Хлеб = 57
Сыр = 48
Печенье = 46
Напиток пиво = 29
Мороженное = 70
Больше всего продано Мороженное = 70
Для продолжения нажмите клавишу Enter
22.2 Организация работ со структурой типа список
Списочные структуры широко используются в организации данных на
компьютерах, например, для устранения коллизий при хешировании данных.
Существует несколько различных структур типа список, для которых в
языке C# разработаны специальные классы: List<T>, ArrayList, LinkedList<T>
и т.д. Наиболее часто используются классы List<T> и ArrayList,
представляющие собой динамические массивы объектов. Обозначение <T>
называется обобщенным типом и позволяет использовать в качестве
элемента списка практически любые типы.
Основные свойства класса ArrayList представлены в таблице 22.2
Таблица 22.2 Основные свойства класса ArrayList
Свойство класса
Описание
public virtuai int Capacity
Это свойство, предназначенное только для
{get;}
чтения, хранит текущую емкость коллекции
public virtal int Count (get;}; Это свойство, предназначенное только для
чтения, хранит текущую длину коллекции
public virtual Object this[int Это свойство позволяет обратиться к
Indx]{set; get;}
элементам по индексу
Основные методы класса ArrayList представлены в таблице 22.3.
Таблица 22.3 Основные методы класса ArrayList
Метод класса
Описание
public static ArrayList (IList: На основе коллекции List создает объект
List);
ArrayList
public virtual int Add(Oblect Добавляет в конец списка новый объект и
Value);
возвращает его индекс
public virtual viod
Добавляет в конец списка несколько
AddRange (ICollection coll)l объектов
public virtual int
Отыскивает объект Value в отсортированном
BinsrySearch(Qbject Value); списке и возвращает его индекс или
отрицательно число, если объект не найден
public virtual void Clean();
Удаляет все элементы коллекции
public virtual bool Containse Возвращает true, если коллекция содержит
(Object Value);
элемент Value
public static ArrayList
Метод возвращает объект, элементы
FixedSize(ArrayList AL);
которого можно изменять, но нельзя
добавлять или удалять
public virtual IEnumerator
Возвращает итератор для объекта
GetEnumerator();
public virtual ArrayList
Возвращает диапазон элементов
GetRange(int Indx, int
Count);
public virtual int
IndexOf(Object Value);
public virtual void Insert (int
Indx, Object Value);
public virtual void
InsertRange(int Indx,
IColliction col);
public virtual bool
IsFixedSize{get;}
public virtual bool
IsReadOnly{get;}
Возвращает индекс элемента со значением
Value
Вставляет элемент Value на нужное место
Indx коллекции
Вставляет диапазон элементов
Возвращает true, если объект имеет
фиксированный размер
Возвращает true, если объект имеет
элементы, предназначенные только для
чтения
Возвращает индекс последнего вхождения в
коллекцию значения Valiue
Устанавливает для элементов коллекции
режим только чтение
Удаляет из коллекции первое вхождение
элемента со значением Value
Удаляет из коллекции элемент с индексом
Indx
Удаляет из коллекции count элементов,
начиная с элемента с индексом Indх
public virtual int
LastIndexOf(Object Value);
public static ArrayList
ReadOnly(ArrayList AL);
public virtual void Remove
(Object Value);
public virtual void
RemoveAt (int Indx);
public virtual void
RemoveRange(int Indx, int
count);
public static ArrayList
Возвращает коллекцию, в которой элемент
Repeat(Object Value, int
Value повторен count раз
count);
public virtual void Reverse(); Изменяет порядок следования элементов на
обратный
public virtual void SetRange Вставляет коллекцию col, начиная с индекса
(int Indx, ICollection col);
Indx
public virtual void Sort();
Сортирует коллекцию
public virtual void
Устанавливает емкость коллекции равной
TrimToSize();
количеству ее элементов
По умолчанию начальная емкость коллекции ArrayList составляет 16
элементов. При расширении коллекции ее емкость удваивается, составляя 32,
64, 128 и т. д. элементов. Метод TrimToSize() отсекает неиспользуемые
элементы.
Рассмотрим учебный пример организации записей типа «Avto» в
списке «Garaj».
using
using
using
using
System;
System.Collections;
System.Linq;
System.Text;
namespace ConsoleApplication1
{
struct Avto
{
public String Marka;
public String Vodilo;
public int Ctoim;
public int God;
}
// Марка автомобиля
//ФИО водителя
// Стоимость автомобиля
// Год выпуска
class Program
{
public static int kol = 0;
public static Avto avto = new Avto();
static ArrayList Garaj = new ArrayList();
public static void addcpi()
{
int b;
int kol;
string buf;
Console.WriteLine("Количество авто в гараже");
buf = Console.ReadLine();
kol = Convert.ToInt32(buf);
for (int i = 0; i < kol; i++)
{
Console.WriteLine("Введите марку {0} авто", i + 1);
buf = Console.ReadLine();
avto.Marka = buf;
Console.WriteLine("Введите ФИО водителя {0} авто",i+1);
buf = Console.ReadLine();
avto.Vodilo = buf;
Console.WriteLine("Введите стоимость {0} авто",i+1);
buf = Console.ReadLine();
b = Convert.ToInt32(buf);
avto.Ctoim = b;
Console.WriteLine("Введите год выпуска {0} авто", i + 1);
buf = Console.ReadLine();
b = Convert.ToInt32(buf);
avto.God = b;
Garaj.Add(avto);
}
}
public static void printcpi()
{
Console.WriteLine("{0,20}, {1, 20}, {2, 15}, {3, 15}",
"Марка авто", "ФИО водителя", "Стоим.авто", "Год вып. авто");
foreach (Avto T in Garaj)
Console.WriteLine("{0,20}, {1, 20}, {2, 15}, {3, 15}",
T.Marka, T.Vodilo, T.Ctoim, T.God);
}
public static void ydalelemcpi()
{
int n;
string buf;
Console.WriteLine("Введите номер удаляемой записи ?");
buf = Console.ReadLine();
n = Convert.ToInt32(buf);
// Удаляем элемент по номеру
Garaj.RemoveAt(n);
}
static void Main()
{
// Создаем и наполняем список
addcpi();
// Печатаем список
printcpi();
// Удаляем элемент списка по номеру
ydalelemcpi();
// Печатаем список
printcpi();
Console.ReadLine();
}
}
}
Работа программы:
Количество авто в гараже
3
Введите марку 1 авто
Лада
Введите ФИО водителя 1 авто
Петров
Введите стоимость 1 авто
2000
Введите год выпуска 1 авто
2007
Введите марку 2 авто
Фиат
Введите ФИО водителя 2 авто
Иванов
Введите стоимость 2 авто
3000
Введите год выпуска 2 авто
2008
Введите марку 3 авто
БМВ
Введите ФИО водителя 3 авто
Сидоров
Введите стоимость 3 авто
4000
Введите год выпуска 3 авто
2006
Марка авто,
ФИО водителя,
Лада,
Петров,
Фиат,
Иванов,
БМВ,
Сидоров,
Введите номер удаляемой записи ?
1
Марка авто,
ФИО водителя,
Лада,
Петров,
БМВ,
Сидоров,
Стоим.авто, Год вып. авто
2000,
2007
3000,
2008
4000,
2006
Стоим.авто, Год вып. авто
2000,
2007
4000,
2006
22.3 Списки с расширенными поисковыми возможностями
Для расширения поисковых возможностей однонаправленных списков в
C# были включены двунаправленные списки, например, LinkedList<T>.
Двунаправленные списки это цепочки узлов, в которых имеются ссылки
как на следующий узел (обычно поле Next), так и на предыдущий узел
(обычно поле Old). Дополнительно каждый узел имеет ссылку на элемент
списка (объект, помещенный в список).
Расширение поисковых возможностей связано с возможность
перемещения по списку в любом направлении. Дополнительным
достоинством двунаправленных списков является простота операций вставки
и удаления элементов списка. Эта процедура сводится к обновлению
нескольких ссылок элементов списка, между которыми выполняется
операция.
Следующей модификацией двунаправленного списка является создание
циклических списков. В циклическом списке последний элемент списка с
помощью указателя Next соединен с его первым элементом, а первый
элемент списка с помощью указателя Old соединен с его последним
элементов.
Особенностью циклического списка является полная равнозначность
элементов (если не учитывать организацию информации внутри самих
элементов списка), т.е. заголовок может находиться на любом элементе
списка. Например, после выполнения некоторой поисковой операции мы
можем установить заголовок на найденный элемент. При следующей
поисковой операции заголовок может быть перемещен на следующий
найденный элемент и т.д.
С учетом возможности перемещения по списку в двух направлениях
можно улучшить алгоритм поиска в списке.
Однако многие стандартные поисковые алгоритмы основаны на
обработке списков, информация элементов которых располагается в
определенном порядке. При этом требуется фиксированное расположение
заголовка списка. Для этих целей было предложено устанавливать заголовок
на элемент, поля которого не содержат смысловой информации (информация
в этот элемент не записывается), а сам элемент необходим как некоторая
начальная точка в циклическом списке.
Такая организация списка получила название списка с выделенным
заголовком.
Для реализации алгоритма двоичного поиска применяются древовидные
структуры, элементы которой имеют два указателя (левый и правый).
22.4 Вопросы для проверки
22.4.1 Как называется простой список, в котором все включения элементов
выполняются в одном конце списка, а все исключения – на другом его
конце?
22.4.2 Как называется простой список, в котором включения и исключения
элементов могут выполняться в любом месте списка?
22.4.3 Что означает запись Public Queue()?
22.4.4 Что делает следующий фрагмент программы:
foreach (int i in ocer)
Console.Write(i + " ");
Console.WriteLine();,
где ocer – заголовок очереди?
22.4.5 Что делает следующий фрагмент программы:
ocer.Clear();,
где ocer – заголовок очереди?
Download