Студопедия

Главная страница Случайная лекция


Мы поможем в написании ваших работ!

Порталы:

БиологияВойнаГеографияИнформатикаИскусствоИсторияКультураЛингвистикаМатематикаМедицинаОхрана трудаПолитикаПравоПсихологияРелигияТехникаФизикаФилософияЭкономика



Мы поможем в написании ваших работ!




Динамический стек

Читайте также:
  1. Аналитико-синтетическая функция коры больших полушарий. Динамический стереотип.
  2. Дисконтированный (динамический) метод оценки эффективности инвестиционных проектов
  3. Тема 3.3. ДИНАМИЧЕСКИЙ РЕЖИМ РАБОТЫ ТРАНЗИСТОРА

Do

Else

Else

head = p.next;

}

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

Рис. 8.11. Односвязный кольцевой список

Для создания двусвязного кольцевогосписка необходимо связать последний элемент с первым как по указателю Next, так и по указателю Pred. Двусвязный кольцевой список показан на рис. 8.12.

Рис. 8.12. Двусвязный кольцевой список

Разумеется, на одном из элементов кольцевого списка должен стоять указатель, и этот элемент условно считается первым.

В качестве примера использования двусвязного кольцевого списка решим следующую задачу. Дети стали в круг, взявшись за руки. Начав отсчет от первого, каждый i-тый выходит из круга, а круг смыкается. Кто останется?

Первая часть задачи — создание списка. Процедура Insert2 вставляет элемент в двусвязный список.

Листинг 8.20. Процедура Insert2 вставляет элемент в двусвязный список

public void Insert2(MyNode2 p, int e)

// вставка элемента в двусвязный список

{ // список пуст, создание первого элемента

if (head == null)

{

head = new MyNode2(e, null, null);

head.next = head;

head.pred = head; // ссылки замыкаем на себя

}

{

MyNode2 t = new MyNode2(e, head.next, head);

head.next.pred = t; head.next = t;

}

}

Вызвав эту процедуру K раз, получим список, содержащий K элементов. Указатель списка стоит на первом включенном в список элементе.

Вторая часть задачи – удаление i-того элемента, считая от первого. Алгоритм прост: отсчитывается заданное количество элементов, требуемый элемент удаляется, указатель на список переносится на следующий за удаленным элемент. Когда в списке останется только один элемент, его поля Pred и Next будут указывать на него самого. Метод CountDel реализует этот алгоритм.

Листинг 8.21. Удаление элемента

public MyNode2 CountDel(MyNode2 p, int step)

{

MyNode2 r = p;

{

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

r = r.next;

MyNode2 t = r.pred; // этот элемент будем удалять

t.pred.next = r; r.pred = t.pred; // замыкаем круг

}

while (r == r.next);

return r;

}

 

Динамический стек— это линейный односвязный список. Работа с этим списком осуществляется по соответствующему принципу: новый элемент кладется на вершину стека, то есть вставляется перед первым элементом списка, и при необходимости взять элемент из стека выбирается значение первого элемента, указатель стека смещается на следующий элемент, а "использованный" элемент удаляется.

Стек реализован в виде класса, поля и методы которого представлены в листинге 8.22.

Листинг 8.22. Класс стека, реализованный динамически

class MyStack

{

Node top;

public void Push(object data) // положить в стек

public object Pop() // взять из стека

public bool IsEmpty() // проверка на пустоту

class Node // узел

}

Развернутый вариант кода класса:

Листинг 8.23. Класс стека, реализованный динамически

namespace SpaceStack

{

class MyStack

{

Node top;

public void Push(object data)

//положить в стек

{

top = new Node(top, data);

}

public object Pop() // взять из стека

{

if (top == null) throw new

InvalidOperationException();

object result = top.data;

top = top.next;

return result;

}

public bool isEmpty() // проверка на пустоту

{

return top == null;

}

class Node // узел

{

public Node next;

public object data;

// конструктор

public Node(Node next, object data)

{

this.next = next;

this.data = data;

}

}

}

}

Следует обратить внимание на то, что метод Pop() — извлечения элемента из стека — внутри себя не делает проверки на пустоту стека. Дело в том, что эта метод должна вызываться только в том случае, когда заранее известно, что стек не пуст. В том случае, когда проверкой (метод IsEmpty) установлено, что стек пуст, решение о дальнейших действиях должно приниматься в вызывающем контексте.

В примере объявляется класс MyStack, принадлежащий пространству имен SpaceStack. Полное имя этого класса — SpaceStack.Stack. Этот класс содержит несколько членов: поле top, два метода Push и Pop, а также вложенный класс Node. Класс Node в свою очередь содержит три члена: поля next и data, а также конструктор. Если исходный код примера хранится в файле MyStack.cs, команда

csc /t:library MyStack.cs

компилирует текст в виде библиотеки, если код не имеет метода Main() и создает сборку с именем MyStack.dll.

В программе C# возможность обращения к открытым типам и членам, содержащимся в конкретной сборке, реализуется посредством ссылки на эту сборку во время компиляции программы. Если в программе используется класс SpaceStack.MyStack, содержащийся в сборке MyStack.dll , то можно решить следующую задачу.

Пример 8.1.Для иллюстрации вышесказанного решим следующую задачу: проверить правильность расстановки скобок в арифметическом выражении.

По правилам записи арифметических выражений первой должна закрываться последняя открывающая скобка, и число открывающих и закрывающих скобок должно совпадать. Будем считать, что в выражении используются три вида скобок: круглые, квадратные и фигурные.

Примечание. Не составит труда, изменив тип информационного поля на string, добавить еще несколько видов скобок, например, операторные скобки begin и end.

Ошибки, которые могут встретиться при расстановке скобок:

· несоответствие открывающей и закрывающей скобок, например: {a×[b+c)};

· непарные скобки, то есть открывающих скобок больше, чем закрывающих (или наоборот).

Поэтому алгоритм проверки должен быть следующим. Выражение просматривается посимвольно, и если встретилась любая открывающая скобка, то она помещается в стек. Если встретилась закрывающая скобка, то из стека берется последняя открывающая и проверяется, соответствует ли она закрывающей. Просмотр выражения заканчивается либо когда обнаружится ошибка, либо когда строка закончится. Если строка закончилась, то необходимо еще проверить стек — не остались ли там непарные открывающие скобки.

Метод BracketTest, приведенная в листинге 8.24, реализует этот алгоритм и возвращает значения:

· –1, если скобки расставлены правильно;

· 0, если не хватает закрывающих скобок;

· номер позиции в строке, на которой стоит "неправильная" скобка.

Листинг 8.24. Проверка скобок в арифметическом выражении

static int BracketTest(string a)

{

char[] begBracket = { '(', '[', '{' };

char[] endBracket = { ')', ']', '}' };

MyStack myStack = new MyStack();

int lenA = a.Length;

bool error = false;

int result = -1;

int i = -1;


<== предыдущая страница | следующая страница ==>
Двусвязные и кольцевые списки | Очереди

Дата добавления: 2014-03-11; просмотров: 492; Нарушение авторских прав




Мы поможем в написании ваших работ!
lektsiopedia.org - Лекциопедия - 2013 год. | Страница сгенерирована за: 0.003 сек.