Скачиваний:
89
Добавлен:
10.05.2014
Размер:
11.4 Mб
Скачать

SP

 

 

 

 

Stack

 

 

 

 

 

 

0

SP

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

...

 

 

 

 

 

 

 

n-1

Стек пуст

SP Stack

0

1

2

...

n-1

Стек полон

Stack

SP

 

 

 

Stack

 

0

 

 

 

 

 

0

 

1

 

 

 

 

 

1

 

2

 

 

 

 

 

2

 

.

 

 

 

 

 

.

 

.

 

 

 

 

 

.

 

.

 

 

 

 

 

.

 

n-1

 

 

 

 

 

n-1

 

 

 

 

 

 

Запись в стек:

 

 

 

 

Чтение из стека:

int push(тип el){

 

 

 

 

int pop(тип &el){

if(SP < n){

 

 

 

 

if( SP > 0){

stack[SP++]=el;

 

 

 

 

el = stack[--SP];

return 1;

 

 

 

 

return 1;

} else

 

 

 

 

}

 

return 0;

 

 

 

 

else

}

 

 

 

 

 

return 0;

}

3. Стек и очередь: определение, основные операции. Особенности выполнения операций при реализации стека и очереди списком.

(Стек и очередь - см. билет 2)

Очередь -реализация списком:

При отображении очереди списком можно использовать линейный и циклический список.

Очередь, реализованная линейным односвязным списком: задаётся двумя указателями - на начало и конец очереди.

Возможные ситуации:

1.Очередь пуста. В исходном состоянии оба указателя имеют пустые значения

(NULL).

2.При записи в очередь первого элемента изменяются оба указателя. Первый элемент в данной ситуации становится последним. Последующие операции добавления элементов изменяют только указатель на конец очереди.

3.При чтении из очереди меняется указатель на начало очереди. Когда будет прочитан последний элемент, очередь станет пустой, и оба указателя (на начало и конец очереди) должны иметь пустое значение.

first

 

first

Запись в очередь

 

 

 

 

 

 

 

 

 

 

first

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

last

 

last

1

0

 

last

 

 

 

 

 

 

 

2

0

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

а) Очередь пуста

 

б)

Элемент списка:

 

 

struct Item{

 

 

Type info;

 

 

Item *next;

 

};

 

 

Item *first,

/*

начало очереди */

*last;

/*

конец очереди */

в)

int putQ(Type el)

 

{

= new Item;

Item *ptr

if(!ptr)

-1; /*

нет памяти */

return

ptr->info

= el;

 

ptr->next

= NULL;

 

if(!first)

очередь пуста */

first = ptr; /*

else

 

 

last->next = ptr;

 

last = ptr;

 

return 0;

 

 

}

 

 

Чтение из очереди

first first first 0

 

 

1

 

 

 

 

 

 

 

 

 

 

 

last

 

 

 

 

 

 

last

2

0

 

last

 

 

 

 

 

 

 

 

 

 

 

 

2

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

а)

б)

Элемент списка: struct Item{

Type info; Item *next;

};

Item *first, /* указатель на начало очереди */ *last; /* указатель на конец очереди */

в) очередь пуста

int getQ(Type &el)

{

Item *ptr = first; if(!first)

return -1; /* очередь пуста */ el = first->info;

first = first->next; delete ptr; if(!first)

last = NULL; return 0;

}

Реализация очереди циклическим односвязным списком:

Достаточно иметь один указатель - на последний элемент (last). Указателем на начало очереди будет являться поле next последнего элемента (первый элемент будет определяться последним элементом).

Возможные ситуации:

1.В исходном состоянии очередь пуста. Указатель на конец очереди имеет пустое значение.

2.При записи нового элемента будет изменяться указатель на конец очереди (будет указывать на записываемый элемент). Так как последний элемент очереди указывает на начало, в поле next записываемого элемента должен быть записан указатель на начало очереди. При записи элемента в пустую очередь, первый элемент является так же и последним, поэтому данный элемент будет указывать сам на себя.

3.При чтении элемента из очереди удаляется первый элемент. Поэтому в последнем элементе (на который указывает конец очереди last) будет меняться значение поле указателя. Когда из очереди будет прочитан последний элемент (перед чтением этот элемент является единственным - и первым, и последним), указатель на конец очереди должен получить пустое значение.

 

 

 

 

 

 

 

 

 

 

 

 

 

Запись в очередь

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

last

 

 

 

last

 

 

 

 

 

 

last

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

а) очередь пуста

 

 

 

б)

 

 

 

 

 

 

в)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int putQ(Type el)

 

 

 

 

 

 

 

 

 

 

 

Элемент списка:

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

struct Item{

 

 

 

 

 

 

 

Item *ptr = new Item;

 

 

Type info;

 

 

 

 

 

 

 

if(!ptr)

 

 

 

 

/* нет памяти */

};

Item *next;

 

 

return -1;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ptr->info = el;

 

 

 

 

 

 

 

 

 

 

 

Item *last; /*

 

 

 

 

 

 

 

if(!last)

 

 

 

 

 

 

 

 

 

 

 

 

конец очереди */

 

 

ptr->next = ptr; /* очередь пуста */

 

 

 

 

 

 

 

 

 

 

 

 

 

else{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ptr->next = last->next;

 

 

 

 

 

 

 

 

 

 

 

 

 

}

last->next = ptr;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

last = ptr;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

return 0;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Чтение из очереди

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

last

 

2

 

 

 

 

last

 

2

 

 

 

 

last

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

а)

 

 

 

 

 

 

 

 

б)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

в) очередь пуста

 

 

 

 

 

 

 

 

 

 

 

int getQ(Type &el)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Элемент списка:

{

Item *ptr;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

struct Item{

 

 

 

 

 

 

 

if(!last)

 

/*

 

очередь пуста */

 

Type info;

 

 

 

 

 

 

 

 

return -1;

 

 

};

Item *next;

 

 

 

 

 

 

 

ptr = last->next; /*

начало очереди */

 

 

 

 

 

 

 

 

 

 

 

 

el = ptr->info;

 

 

 

 

 

 

 

 

 

 

Item *last; /* конец очереди */

if(last == ptr)

/*

 

прочитан последний элемент */

 

last = NULL;

 

else

last->next = ptr->next; delete ptr;

return 0;

}

Стек -реализация списком:

При отображении стека списком используется линейный односвязный список.

Возможные состояния:

1.В исходном состоянии, когда стек пуст, вершина стека - указатель имеет пустое значение SP=NULL. Создаваемый элемент включается в начало списка.

2.Ситуация "стек полон" достигается, когда создание нового элемента заканчивается неудачей (функция выделения памяти malloc()или оператор языка С++ выделения памяти new возвращают значение NULL, что свидетельствует об ошибке)

3.При чтении из стека, реализованного списком, первый элемент исключается из списка. Информация из элемента списка передаётся как результат операции чтения.

struct Item{

Исходное состояние -

 

 

 

SP

 

 

тип info;

стек пуст:

 

 

 

 

 

 

 

 

 

 

 

 

 

Item *next;

Item *SP = NULL;

 

 

 

 

0

 

 

 

 

 

} ;

 

 

 

 

 

 

 

 

 

SP

 

 

 

 

 

 

 

 

 

 

 

 

SP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

0

 

 

 

 

 

 

 

2

 

 

 

 

 

 

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Новый элемент

 

 

 

 

 

а) До чтения

 

 

 

 

 

 

 

 

 

 

 

 

а) До записи

 

 

SP

 

 

 

 

 

 

 

 

 

 

 

 

SP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

 

 

 

1

0

 

 

 

 

 

 

 

1

0

 

3

 

 

 

 

 

 

 

 

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Элемент прочитан

 

Элемент записан

 

 

 

 

 

 

 

б) После записи

 

 

 

 

 

б) После чтения

 

Запись в стек:

 

 

 

 

Чтение из стека:

 

int push(тип el){

 

 

 

 

int pop(тип &el){

 

 

Item *tmp = new Item;

 

 

 

 

 

Item *tmp = SP;

 

 

if(!tmp)

 

 

 

 

 

if(!top)

 

 

return 0;

 

 

 

 

 

 

return 0;

 

 

tmp->info = el;

 

 

 

 

 

SP = SP->next;

 

 

tmp->next = SP;

 

 

 

 

 

el = tmp->info;

 

 

SP = tmp;

 

 

 

 

 

delete tmp;

 

}

return 1;

 

 

 

}

return 1;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4. Просматриваемая динамическая таблица-вектор: определение, основные операции, особенности их реализации.

(Алгоритмы и структуры данных, лекция 17.03.2004)

Таблица:

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

Ключ Информация

Ключ - уникален для всех записей таблицы. Может быть достаточно сложным и иметь внутреннюю структуру (например, идентифицирующая информация + номер версии). Ключ однозначно идентифицирует информацию элемента таблицы.

Операции с таблицей:

1.Добавление элемента. Включение нового элемента в таблицу (при этом, чтобы сохранить уникальность ключа, необходимо убедиться, что в таблице дубликатов ключа нет)

2.Доступ к элементу. Поиск (самая главная операция в таблицах!)

3.Удаление элемента из таблицы (при удалении - так же требуется сначала найти удаляемый элемент).

Критерии классификации таблиц:

1.Тип операций (способ доступа):

1.1.статические (операции включения/удаления не разрешены; определена только операция поиска).

1.2.динамические (определены все операции с таблицей).

2.Организация операции поиска (способ организации таблицы):

2.1.просматриваемые

2.2.упорядоченные

2.3.таблицы с вычисляемым входом

2.3.1.таблицы произвольного доступа

2.3.2.хэш-таблицы (перемешанные)

Таблицы могут быть представлены (в памяти):

1.вектором

2.списком

3.семейством списков.

Просматриваемая таблица:

Просматриваемая таблица - таблица, в которой не устанавливаются никакие правила по отношению к размещению ключей в таблице.

Особенности:

1.Наиболее легко реализуется

2.Самые медленные таблицы. Целесообразно использовать только для небольших таблиц (несколько десятков элементов).

Обычно просматриваемые таблицы бывают динамические.

Просматриваемая динамическая таблица-вектор Операции.

1.Включение элемента. Поскольку разрешена операция включения, необходимо иметь информацию о наличии в таблице свободных позиций. При наличии нескольких свободных позиций, требуется решить, в какую именно будет добавлен элемент.

2.Удаление элемента. Для фиксации свободных и занятых элементов таблицы, в элемент таблицы включают дополнительное поле 0/1 - поле занятости.

3.Поиск. На реализацию поиска может повлиять наличие в таблице свободных элементов (следует учитывать, свободен элемент или занят).

4."Сборка мусора" (garbage)

Проблемы:

1.Как искать?

2.Как учитывать переполнение вектора?(операция "сборка мусора")

Рекомендации:

1.Просматриваемые таблицы небольшие по размеру

2.Помечать удалённые элементы + периодически выполнять "сборку мусора"

Возможные ситуации:

1.В исходном состоянии таблица пуста и все элементы помечены как свободные (в поле занятости =0).

2.При включении нового элемента в таблицу, требуется найти подходящий свободный элемент. Критерием для выбора может служить L - длина доступа (количество элементов таблицы, которые необходимо просмотреть, прежде чем будет найдена свободная позиция). Можно обеспечить L=1, если все операции включения выполнять в конец таблицы (и ввести переменную int n, которая определяет первый свободный элемент в конце таблицы). В исходном состоянии n=0. Каждая операция добавления увеличивает n на 1.

3.При удалении элемента достаточно установить "0" в поле занятости. Не стоит при удалении элемента из середины таблицы перемещать информацию из конца таблицы в освободившуюся позицию, т.к. это может привести к увеличению времени выполнения операции (поэтому n при удалении не меняет своего значения).

4.Операция сборки мусора. После включения/удавления с течение времени возникает ситуация, когда свободных позиций в конце таблицы нет (n = M) в то время, как в

const int M = 20; struct Item{
int busy; int key; Type info;

середине таблицы есть множество элементов, помеченных как свободные. В этом случае перед включением нового элемента, необходимо реорганизовать таблицу, собрав все свободные элементы в конце таблицы и изменив её текущий размер n. В зависимости от того, насколько часто прикладная программа выполняет операции включения/удаления, может оказаться целесообразным выполнить операцию сборки мусора, чтобы последующие операции включения не требовали дополнительных расходов. Замечание: можно включать новый элемент в первую найденную свободную позицию (исключив операцию сборки мусора), но увеличив время выполнения операции включения.

Примеры:

Конкретная реализация вспомогательных функций (удаление информации и создание копии данных) зависит от типа информации, включаемой в таблицу (тип Type), и определяется разработчиком соответствующего приложения.

/* Максимальный размер таблицы */

/* поле занятости */ /* ключ */

/* информация */

};

Item table[M]; /* Объявление таблицы как внешней (вне функций) приводит к тому, что все элементы инициализируются нулем; поэтому можно не устанавливать явно

значения 0 в поле busy всех элементов при создании таблицы */ int n = 0;

/* поиск элемента в таблице */ int search(int k)

{

int i;

for(i = 0; i < n; i++)

if(table[i].busy && table[i].key == k)

return i;

/* элемент найден – он занят и имеет искомый ключ */

return -1;

/* элемент не найден

*/

}

 

 

 

/* удаление элемента */

 

 

 

int del(int k)

 

 

 

{

 

 

 

int l;

 

 

 

if((l = search(k)) < 0)

 

/* указанного элемента в таблице нет */

return -1;

 

table[l].busy = 0;

/* "удаление" элемента */

delInfo(table[I].info);

 

 

 

return 0;

 

 

 

}

 

 

 

/* "сборка мусора" */

 

 

 

int garbage()

 

 

 

{

 

 

 

int i, cur = n;

 

 

 

n = 0;

 

 

 

for(i = 0; i < cur; i++)

/* элемент занят */

if(table[i].busy){

if(i != n)

 

/* элемент должен быть перемещен */

table[n] = table[i];

/* перемещение элемента */

n++;

 

 

 

}

 

/* в таблице нет свободного места */

return n == M ? -1 : 0;

 

}

 

*/

 

/* включение нового элемента в таблицу

 

int insert(int k, Type in)

 

 

 

{

 

 

 

if(search(k) >= 0)

 

/* в таблице есть элемент с заданным ключом */

return -1;

 

Соседние файлы в папке docs