- •Конспект лекций по курсу
- •Абстрактные структуры данных
- •Определение
- •Базовые структуры данных
- •Очереди и стеки
- •Деревья
- •Внутренние структуры данных
- •Отображение абстрактных структур данных на внутренние
- •Строка-вектор
- •1. Функция сцепления двух строк
- •2. Функция поэлементного сравнения двух строк
- •3. Функция разбиения строки.
- •4. Функция нахождения подстроки в строке
- •Строка-список
- •1. Сцепление двух строк
- •2. Поэлементное сравнение двух строк
- •3. Разбиение строки на части
- •4. Функция нахождения подстроки в строке
- •Стек-вектор
- •Стек-список
- •Очереди
- •Очередь-вектор
- •Очередь-список
- •Деревья
- •Классификация таблиц
- •Способ работы с таблицей
- •Способ доступа к таблице
- •Просматриваемые таблицы
- •Статическая просматриваемая таблица-вектор
- •Динамическая просматриваемая таблица-вектор
- •Просматриваемая таблица-список
- •Упорядоченные таблицы
- •Упорядоченная таблица-вектор
- •Динамическая упорядоченная таблица – вектор
- •Упорядоченная таблица – двоичное дерево
- •Перемешанные таблицы
- •Открытое перемешивание
- •Перемешивание сцеплением
2. Поэлементное сравнение двух строк
Алгоритм сравнения двух строк достаточно простой, поэтому далее приводится только текст функции.
struct Item{
char s;
Item *next;
};
int compare(Item *first, Item *second)
{
/* символы строк, участвующие в формировании результата сравнения */
char c1 = '\0', c2 = '\0';
while(first && second && first->s == second->s){
first = first->next;
second = second->next;
}
/* если строки не равны, тогда один или оба указателя –first и second – не пусты */
if(first) /* не пуст */
c1 = first->s;
if(second) /* не пуст */
c2 = second->s;
return c1 - c2;
}
Текст данной функции также приводится в файле stringl.cpp.
3. Разбиение строки на части
В результате разбиения строки для исходного списка создаются новые подсписки, каждый из которых определяет соответствующий фрагмент исходной строки. Исходный список сохраняется. Количество подсписков определяется тем, сколько раз в исходной строке встретился символ-разделитель (следует учитывать, что в конце исходной строки символ-разделитель может отсутствовать). Символы-разделители в подсписки не входят. Функция формирует массив указателей на выделенные подсписки и в качестве результата возвращает количество выделенных фрагментов и указатель на первый элемент массива указателей.
Данная функция также сначала определяет количество подсписков, а затем выделяет требуемую память под результат и формирует подсписки и массив указателей на них. Принципы работы данной функции иллюстрируются рис. II–20.

Рис. II–20
Схема алгоритма приведена на рис. II–21.

Рис. II–21
Память выделяется динамически, с помощью оператора new(это следует учитывать в приложении при освобождении выделенной памяти).
Текст функции приводится ниже и в файле stringl.cpp.
int split(Item *str, char fs, Item **&mas)
{
int i, cnt;
Item **pa, *ptr;
/* подсчитать количество подсписков; при подсчете учитываем, что
* последним символом в списке может быть символ-разделитель
*/
for(ptr = str, cnt = 1; ptr; ptr = ptr->next)
if(ptr->s == fs && ptr->next)
cnt++;
/* выделить требуемую память под указатели на подсписки */
mas = new Item *[cnt];
ptr = str;
for(i = 0; i < cnt; i++){
/* сформировать указатель на очередной подсписок */
pa = mas + i;
*pa = NULL;
/* сформировать очередной подсписок */
for(; ptr && ptr->s != fs; ptr = ptr->next){
*pa = new Item;
(*pa)->s = ptr->s;
(*pa)->next = NULL;
pa = &(*pa)->next;
}
/* пропустить символ-разделитель */
if(ptr)
ptr = ptr->next;
}
return cnt;
}
4. Функция нахождения подстроки в строке
Прототип функции может иметь следующий вид:
struct Item{
char s;
Item *next;
} Item;
Item * substr(Item *string1, Item *string2);
Функция возвращает указатель на первое вхождение подстроки string2в строкуstring1илиNULL, если подстрокаstring2не входит в строкуstring1. Схема алгоритма функции приведена на рис.II–22.

Рис. II–22
Текст функции приводится ниже и в файле stringl.cpp.
struct Item{
char s;
Item *next;
} Item;
Item * substr(Item *string1, Item *string2)
{
Item *ptr1, *ptr2;
for(; string1; string1 = string1->next){
/* начинаем сравнение двух строк-списков,
* запомнив текущий символ первой строки
*/
for(ptr1 = string1, ptr2 = string2; ptr1 && ptr2;
ptr1 = ptr1->next, ptr2 = ptr2->next)
if(ptr1->s != ptr2->next)
break; /* символы не совпали –
* продолжаем просмотр первой строки */
if(!ptr2)
return string1; /* все символы строк совпали */
}
return NULL;
}
Стеки
Динамическую структуру данных стек можно отображать и вектором, и списком.
Как было сказано ранее, стек характеризуется одним концом – вершиной стека. Операции занесения информации в стек и выборки из стека выполняются всегда через вершину стека. При чтении информации из стека необходимо проверять ситуацию "стек пуст"; данная ситуация представляет собой специальный случай штатной ситуации, требующий, возможно, особой обработки в программе, работающей со стеком. При записи информации, учитывая, что данные размещаются в некотором ограниченном пространстве, следует проверять ситуацию "стек полон", при которой запись в стек невозможна. Данная ситуация является нештатной и свидетельствует, как правило, о недостаточной проработке прикладной программы (или наличии ошибки в программе). Возникновение такой ситуации в программе требует анализа правильности ее функционирования и принятия необходимых мер.
Способы анализа таких ситуаций и реакции на них зависят от того, как стек отображается в оперативной памяти. Рассмотрим особенности использования каждой структуры.
