- •Предназначено студентам очной формы обучения.
- •Введение
- •1. Оценки сложности алгоритмов
- •1.1. Определение понятия алгоритм
- •1.2. Оценка сложности алгоритмов
- •2. Линейные структуры данных
- •2.1. Методы организации и хранения линейных списков
- •2.2. Операции со списками при последовательном хранении
- •2.3. Операции со списками при связном хранении
- •2.4. Организация двусвязных списков
- •Задания для самоконтроля
- •2.5. Стеки и очереди
- •2.6. Сжатое и индексное хранение линейных списков
- •3. Сортировка и слияние
- •3.1. Пузырьковая сортировка
- •3.2. Сортировка вставкой
- •3.3. Сортировка посредством выбора
- •3.4. Сортировка квадратичной выборкой
- •3.5. Слияние списков
- •3.6. Сортировка списков путем слияния
- •3.7. Быстрая и распределяющая сортировки
- •4. Поиск
- •4.1. Последовательный поиск
- •4.2. Бинарный поиск
- •4.4. Методы вычисления адреса
- •4.5. Выбор в линейных списках
- •5. Рекурсия
- •6. Алгоритмы на графах и сетях
- •6.1. Исходные понятия
- •6.2. Матричные представления графов
- •6.3. Другие представления графов
- •6.4. Поиск в глубину как система исследования графа
- •6.5. Перебор цепей поиском в глубину
- •6.6. Взвешенные графы. Ориентированные графы
- •6.7. Нахождение фундаментального множества циклов
- •6.8. Выявление мостов и точек сочленений
- •6.9. Поиск в ширину как система исследования графа
- •6.10. Кратчайшие пути, ведущие от заданного узла X ко всем прочим
- •6.11. Алгоритм Дейкстры нахождения кратчайших путей во взвешенном графе
- •6.12. Улучшения алгоритма Дейкстры
- •6.13. Построение кратчайшего каркаса
- •6.14. Нахождение всевозможных кратчайших путей в графе
- •6.15. Потоковые задачи
- •6.16. Пример практической задачи на графах
- •7. Генераторы случайных и псевдослучайных последовательностей
- •7.1. Общая постановка задачи
- •7.3. Генератор случайных чисел, поставляемый с системой
- •7.4. Генератор с малым кодом
- •7.5. Генератор Парка-Миллера
- •7.6. Улучшенная версия генератора Парка-Миллера
- •7.7. Быстрый генератор для 32-битового представления целых и действительных чисел
- •7.8. Алгоритм л'Экюера, комбинирующий две последовательности
- •Оглавление
- •7. Генераторы случайных и псевдослучайных последовательностей 144
- •394026 Воронеж, Московский просп., 14
2.4. Организация двусвязных списков
Связанное хранение линейного списка называется списком с двумя связями или двусвязным списком, если каждый элемент хранения имеет два компонента указателя (ссылки на предыдущий и последующий элементы линейного списка).
В программе двусвязный список можно реализовать с помощью описаний:
typedef struct ndd {
float val; /* значениеэлемента */
struct ndd *n; /* указатель на следующий элемент*/
struct ndd *m; /* указатель на предыдующий элемент */
} NDD;
NDD *dl, *p, *r;
floatnov;
Графическая интерпретация метода связанного хранения списка F=< 2,5,7,1 > как списка с двумя связями приведена на рис.9.
Рис. 9. Схема хранения двусвязного списка
Вставка нового узла со значением new за элементом, определяемым указателем p, осуществляется при помощи операторов:
r=(NDD*) malloc(sizeof(NDD));
r->val=nov;
r->m=p;
r->n=p->n;
p->n=r;
Удаление элемента, следующего за узлом, на который указывает p:
r=p->n;
p->n=(p->n)->n;
((p->n)->n)->m=p;
free(r);
Связанное хранение линейного списка называется циклическим списком, если его последний указывает на первый элемент, а указатель dl – на последний элемент списка.
Схема циклического хранение списка F=< 2,5,7,1 > приведена на рис.10.
Рис. 10. Схема циклического хранения списка
При решении конкретных задач могут возникать разные виды связанного хранения.
Пусть на входе задана последовательность целых чисел B1, B2,..., Bn из интервала от 1 до 9999, и пусть Fi (1 i 9999) по возрастанию. Составить процедуру для формирования Fn в связанном хранении и возвращения указателя на его начало.
При решении задачи в каждый момент времени имеем упорядоченный список Fi и при вводе элемента Bi +1 вставляем его в нужное место списка Fi, получая упорядоченный список Fi +1. Здесь возможны три варианта: в списке нет элементов; число вставляется в начало списка; число вставляется в конец списка. Чтобы унифицировать все возможные варианты, начальный список организуем как связанный список из двух элементов <0,10000>.
Рассмотрим программу решения поставленной задачи, в которой указатели dl, r, p, v имеют следующее значение: dl указывает начало списка; p, v - два соседних узла; r фиксирует узел, содержащий очередное введенное значение in.
#include <STDIO.H>
#include <STDLIB.H>
#include <conio.h>
typedef struct str1 {
float val;
struct str1 *n;
} ND;
ND *arrange(void);
void main()
{
ND *p=arrange();
ND *buf=p;
clrscr();
while(1)
{
printf("\n %f ",p->val);
p=p->n;
if( p==buf ) return;
}
}
ND *arrange() /*формирование упорядоченного списка */
{
ND *dl, *r, *p, *v;
float in=1;
char *is;
dl=(ND*) malloc(sizeof(ND));
dl->val=0; /*первыйэлемент*/
dl->n=r=(ND*) malloc(sizeof(ND));
r->val=10000;
r->n=dl; /*последний элемент */
p=dl; // предыдущий
v=r; // следующий
while(1)
{
scanf("%s",is);
if(*is=='q') return(dl);
in=atof(is);
r=(ND*) malloc(sizeof(ND));
r->val=in;
r->n=v;
p->n=r;
p=p->n;
}
return(dl);
}