Раздел 31.ppt
- Количество слайдов: 32
Тема 13. Общая характеристика динамических структур
Статические структуры данных § создаются в момент определения и уничтожаются автоматически при выходе программы из области их действия § характеризуются фиксированным размером выделенной для них памяти § Например, int a[100] - массив, занимающий sizeof(int)*100 байт, хотя в программе может реально использоваться лишь несколько первых элементов массива.
Задачи, в которых невозможно или неэффективно использование статических структур n n n До начала работы с данными невозможно определить, сколько памяти потребуется для их хранения До начала работы с данными возможно определить только верхнюю границу диапазона, которая очень велика Размер данных известен, но они очень гибкие по структуре (например, данные часто удаляются и вставляются в произвольные места структуры, задачи сортировки).
Динамические структуры данных n способны увеличиваться и уменьшаться в размерах в процессе работы программы n память выделяется (и освобождается) по мере необходимости отельными блоками, связанными друг с другом указателями n могут занимать несмежные участки оперативной памяти INF NEXT INF NULL
Динамические структуры данных n Для реализации элементов динамической структуры данных в С++ используют тип данных, называемый структура (struct). struct имя_типа { тип имя_поля 1; тип имя поля 2; … тип имя_поля n; } [список определений];
Динамические структуры данных n Элемент любой динамической структуры данных представляет собой структуру, содержащую по крайней мере два поля: n n n для хранения данных для указателя на эту же структуру. Например, элемент списка целых чисел имеет вид struct element { int inf; element *next; }; n Полей данных и указателей может быть несколько.
Каждая динамическая структура характеризуется n взаимосвязью элементов; n набором типовых операций над этой структурой.
В случае динамической структуры нужно решить следующие вопросы: каким образом может расти и сокращаться данная структура; n каким образом можно включить в структуру новый и удалить существующий элемент; n как можно обратиться к конкретному элементу структуры для выполнения над ним определенной операции. n
Доступ по индексу в динамических структурах, очевидно, менее удобен, чем это было в случае массивов, так как любой элемент при изменении размеров структуры может изменить свою позицию. Поэтому обычно доступ к элементам динамической структуры относительный: найти первый элемент, найти следующий (предыдущий) элемент по отношению к текущему, найти последний элемент и т. п. )
Достоинства динамических структур – в возможности обеспечения значительной изменчивости структур, а именно: n размер структуры ограничивается только доступным объемом машинной памяти; n при изменении логической последовательности элементов структуры требуется не перемещение данных в памяти, а только коррекция указателей; n большая гибкость структуры (произвольная вставка и удаление элементов).
Недостатки динамических структур: на поля указателей (связок) расходуется дополнительная память; n доступ к элементам связной структуры может быть менее эффективным по времени. n Поэтому связное представление практически никогда не применяется в задачах, где логическая структура данных имеет вид массива - с доступом по номеру элемента, но часто применяется в задачах, где логическая структура требует другой исходной информации доступа (списки, деревья и т. д. ).
Из динамических структур в программах чаще всего используют: n линейные списки; n частные случи списков – стеки и очереди; n бинарные деревья.
Тема 14. Динамические списки Однонаправленный (односвязанный) линейный список Голова списка INF NEXT INF NULL § INF - информационное поле, § NEXT - указатель на следующий элемент списка. § Каждый список должен иметь особый элемент, называемый головой списка. § В поле указателя последнего элемента списка находится специальный признак NULL. § Существует возможность перемещения по списку лишь в одну сторону.
Двунаправленный (двусвязный) линейный список Голова списка NULL INF n n n Указатель конца NEXT PREV INF NULL INF - информационное поле, NEXT - указатель на следующий элемент, PREV - указатель на предыдущий элемент. В крайних элементах соответствующие указатели должны содержать NULL, как и показано на рисунке. Для удобства обработки списка добавляют еще один особый элемент - указатель конца списка.
Кольцевой список может быть организован на основе как односвязного, так и двусвязного списков. При этом в односвязном списке указатель последнего элемента должен указывать на первый элемент; в двухсвязном списке в первом и последнем элементах соответствующие указатели переопределяются следующим образом: Голова списка PREV INF NEXT
Создадим однонаправленный список студентов и их оценок. Каждый элемент списка будет иметь следующий вид: struct student { char *fio; int mark; student *next; } Для формирования списка требуется иметь по крайней мере один указатель – на начало списка (голова списка). student * begin=NULL; и один вспомогательный указатель student *adr; .
Процедура создания стека Стек реализует принцип LIFO last in – first out, последним пришел – первым вышел. fio mark next begin NULL adr
Создание списка по принципу стека Создадим список студентов как стек, постоянно передвигая указатель begin и последний созданный элемент делая головой списка. void vvod 1 () { int n; cout<< “Введите количество студентов ”; cin>>n; const int dlin=20; char f[dlin]; // вспомогательный массив для хранения //введенной фамилии студента
for (int i=1; i<=n; i++) { adr=new(student); cout<< “Введите фамилию ”; cin. getline(f, dlin); adr->fio=new (char [strlen(f)+1]); strcpy(adr->fio, f); cout<< “Введите оценку ”; cin>>(adr->mark); adr->next=begin; begin=adr; } }//vvod 1()
Процедура создания очереди Очередь реализует принцип FIFO first in – first out первым пришел – первым вышел adr fio mark next begin fio mark next NULL
Создание списка по принципу очереди Создадим список студентов как очередь, один раз выделив память под первый элемент и не передвигая указатель begin и последний созданный элемент делая головой списка. void vvod 2 () { int n; cout<< “Введите количество студентов ”; cin>>n; const int dlin=20; char f[dlin]; // вспомогательный массив для хранения //введенной фамилии студента
for (int i=1; i<=n; i++) { if (begin==NULL) // выделение памяти под первый //элемент списка { begin=new (student); adr=begin; } else // выделение памяти под очередной элемент списка { adr->next=new(student); adr=adr->next; }
//заполнение элементов списка cout<< “Введите фамилию ”; cin. getline(f, dlin); adr->fio=new (char [strlen(f)+1]); strcpy(adr->fio, f); cout<< “Введите оценку ”; cin>>(adr->mark); adr->next=NULL; } }//vvod 2();
Для списка обычно определяют следующие процедуры: n добавления элемента в конец списка; n поиска заданного элемента; n вставка элемента до или после заданного элемента; n сортировка списка; n удаления заданного элемента; n удаление списка.
Добавления элемента в стек fio mark next begin fio mark next NULL adr
Процедура добавления студента записывается следующим образом: void add() { student *adr; char f[dlin]; adr=begin; begin=new(student); cout<<"n. Enter fio "; gets(f); begin->fio=new (char [strlen(f)+1]); strcpy(begin->fio, f); cout<<"n. Enter mark "; cin>> begin->mark; begin->next=adr; }
Добавления элемента в очередь adr fio mark next begin fio mark next NULL
Процедура добавления студента записывается следующим образом: void add() { student *adr; char f[dlin]; if (begin==NULL) { begin=new (student); adr=begin; } else { adr=begin; while (adr->next) adr=adr->next; adr->next=new(student); adr=adr->next; } cout<< “Введите фамилию ”; cin. getline(f, dlin); adr->fio=new (char [strlen(f)+1]); strcpy(adr->fio, . f); cout<< “Введите оценку ”; cin>>(adr->mark); adr->next=NULL; }
Вставка элемента до заданного fio mark next begin fio mark next NULL adr
Вставка элемента до заданного begin fio mark next adr 1 fio mark next NULL fio mark next
Процедура добавления нового студента до студента с заданной фамилией void add 2(char * f) { student *adr; if (strcmp (begin->fio, f)==0) add(); else { adr=begin; while (adr->next && strcmp (adr->next->fio, f)) adr=adr->next;
if (adr->next) { student * adr 1=adr->next; adr->next=new(student); cout<< “Введите фамилию ”; cin. getline(f 1, dlin); adr->next->fio=new (char [strlen(f 1)+1]); strcpy(adr->next->fio, f 1); cout<< “Введите оценку ”; cin>>(adr->next->mark); adr->next=adr 1; } else cout<< “Нет студента с фамилией”<<f; }//add 2()
Раздел 31.ppt