Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лаба 1

.pdf
Скачиваний:
1
Добавлен:
18.02.2023
Размер:
122.05 Кб
Скачать

Лабораторная работа № 1-2

Тема: Программирование с использованием динамических структур: списки Цель: Изучить методы организации списочных структур в динамической памяти. Реализовать алгоритмы добавления, удаления и сортировки списков.

Краткая теория

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

Виды списков:

с последовательным хранением элементов (рисунок 1);

со связанным хранением элементов (рисунок 2);

со смешанным хранением элементов (рисунок 3).

list

DATA

DATA

...

DATA

 

 

 

 

 

Рисунок 1 – Список с последовательным хранением элементов

DATA

DATA

DATA

NEXT

NEXT

NEXT

 

 

 

 

 

 

...

 

 

 

 

PREV

 

 

 

PREV

 

PREV

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рисунок 2 – Список со связанным хранением элементов

DATA

 

DATA

 

 

 

list

...

DATA

Рисунок 3 – Список со смешанным хранением элементов

Для работы со списками с последовательным хранением переменных необходимы следующие типы и переменные:

тип *list = NULL; //Указатель на список

int cnt = 0;//Количество элементов в списке

Тип – системный или пользовательский тип даны, значения данного типа хранятся в списке.

Функция добавления элемента в конец списка: int Add(тип val)

{

тип *tmp = calloc(cnt+1,sizeof(тип));

if(!tmp) return 0;

if(cnt) memcpy(tmp,list,cnt*sizeof(тип)); tmp[cnt] = val;

cnt++; if(list) free(list); list = tmp; return 1;

}

Функция вставки элемента в список: int Ins(тип val, int ind)

{

if(ind < 0) return 0;

if(ind >= cnt) return Add(val);

тип *tmp = calloc(cnt+1,sizeof(тип)); if(!tmp) return 0; memcpy(tmp,list,ind*sizeof(тип)); tmp[ind] = val;

memcpy(&tmp[ind+1],&list[ind],(cnt-ind)*sizeof(тип)); cnt++; free(list); list = tmp;

return 1;

}

Функция удаления элемента из списка: int Del(int ind)

{

if((ind<0)||(ind >= cnt)) return 0; if(cnt == 1) {Destroy(); return 1;} тип *tmp = calloc(cnt-1,sizeof(тип)); if(!tmp) return 0; memcpy(tmp,list,ind*sizeof(тип));

memcpy(&tmp[ind],&list[ind+1],(cnt-ind-1)*sizeof(тип)); cnt--; free(list); list = tmp;

return 1;

}

Функция удаления всего списка: void Destroy(void)

{

if(list) free(list); list = NULL; cnt = 0;

}

Типы и переменные, необходимые для работы со списком со связанным хранением

элементов (двунаправленные списки):

 

 

 

 

typedef struct _Element{

//Структура для элемента списка

тип val;

//Поле данных

элемента

списка

struct _Element *next, *prev; //Указатели

на

следующий и

} Element;

//предыдущий

элементы

списка

Element *Head = NULL, //Указатель на первый элемент

в списке

*Cur = NULL; //Указатель на текущий элемент в списке

Функция добавления элемента в конец списка: int Add(тип val)

{

Element *tmp = (Element *)malloc(sizeof(Element)); if(!tmp) return 0;

if(!Head){ Head=tmp;

tmp->Prev=NULL; tmp->Next=NULL;

}else{

if(!Curr) Curr=Head; while(Curr->Next) Curr=Curr->Next; Curr->Next=tmp;

tmp->Prev=Curr; tmp->Next=NULL;

}

tmp->Val=val; Curr=tmp; return 1;

}

Функция вставки элемента перед текущим элементом в списке: int Ins(тип val)

{

if(!Curr) return Add(val);

Element * tmp=(Element *)malloc(sizeof(Element)); if(!tmp) return 0;

tmp->Next=Curr; tmp->Prev=Curr->Prev; Curr->Prev=tmp;

if(tmp->Prev) tmp->Prev->Next=tmp; else Head=tmp;

tmp->Val=val; Curr=tmp; return 1;

}

Функция удаления текущего элемента: int Del()

{

if(Curr==NULL) return 0; Element *tmp=Curr->Prev; if(!tmp){

Head=Head->Next; Head->Prev=NULL;

}else{ tmp->Next=Curr->Next;

if(Curr->Next) Curr->Next->Prev=tmp;

}

free(Curr); Curr=tmp; return 1;

}

Функция удаления всего списка: void Destroy(void)

{

while(Head){

Curr=Head; Head=Head->Next; free(Curr);

}

Curr=NULL; Head=NULL;

}

Функция сортировки вставками двунаправленного списка: void SortIns(void)

{

Element *tmp, *cur; if((!Head)||(!Head->Next)) return; Curr = Head->Next;

while(Curr){ tmp = Curr;

cur = Curr->Prev; Curr = Curr->Next; cur->Next = tmp->Next;

if(tmp->Next) tmp->Next->Prev = cur; while(cur&&(cur->val > tmp->val)) cur = cur->Prev; if(cur){

tmp->Next = cur->Next; tmp->Prev = cur; cur->Next = tmp;

if(tmp->Next) tmp->Next->Prev = tmp;

}else{

tmp->Next = Head; tmp->Prev = NULL; Head->Prev = tmp; Head = tmp;

}

}

}

Функция сортировки пузырьком двунаправленного списка: void SortBub(void)

{

if(!Head) return; int Flag = 1; while(Flag){

Flag = 0; Curr = Head;

while(Curr->Next){

if(Curr->val > Curr->Next->val){ Exchange();

Flag = 1;

}else Curr = Curr->Next;

}

}

}

void Exchange(void)

{

Element *tmp = Curr->Next; Curr->Next = tmp->Next; tmp->Prev = Curr->Prev;

if(Curr->Next != NULL) Curr->Next->Prev = Curr; if(tmp->Prev != NULL) tmp->Prev->Next = tmp; tmp->Next = Curr;

Curr->Prev = tmp;

if(Curr == Head) Head = tmp;

}

Для работы со списком со смешанным хранением элементов необходимы следующие типы и переменные:

тип

**list = NULL;

//Указатель на список

int count = 0,

//Текущее количество элементов в списке

 

size = 0;

//Общее число элементов списка

Функция создания списка: int Create(int base)

{

list = (тип **)calloc(base,sizeof(тип*)); if(!list) return 0;

for(int i=0;i<base;i++) list[i] = NULL; count = 0; size = base;

return 1;

}

Функция модификации размера списка:

int Resize(int mode)// 0 – сжать, 1 - увеличить

{

тип **tmp;

 

if(mode){

//mode == 1

tmp = (тип **)calloc(size+1,sizeof(тип*)); if(!tmp) return 0; memcpy(tmp,list,size*sizeof(тип*)); free(list); list = tmp; list[size++] = NULL;

}else{ //mode == 0 if(count==size) return 0;

tmp = (тип **)calloc(count,sizeof(тип*)); if(!tmp) return 0; memcpy(tmp,list,count*sizeof(тип*)); free(list); list = tmp; size = count;

}

return 1;

}

Функция добавления элемента в конец списка: int Add(тип value)

{

if((count == size)&&!Resize(1)) return 0; тип *tmp = (тип *)malloc(sizeof(тип)); if(!tmp) return 0;

*tmp = value; list[count++] = tmp; return 1;

}

Функция вставки элемента в список: int Ins(тип value, int index)

{

if((index <0)||(index>=count)) return Add(value); if((count == size)&&!Resize(1)) return 0;

тип *tmp = (тип *)malloc(sizeof(тип)); if(!tmp) return 0;

*tmp = value;

for(int i=count;i>index;i--) list[i] = list[i-1]; list[index] = tmp; count++;

return 1;

}

Функция удаления элемента из списка:

int Del(int index)

{

if((index<0)||(index>=count)) return 0; free(list[index]);

for(int i=index;i<count-1;i++) list[i] = list[i+1]; list[--count] = NULL;

return 1;

}

Функция удаления всего списка: void Destroy(void)

{

for(int i=0;i<count;i++) free(list[i]); free(list);

count = size = 0;

}

Функции для сортировки списка:

int Cmp(const void *ptr1, const void *ptr2)

{

тип a, b;

a= **(тип**)ptr1;

b= **(тип**)ptr2;

return (a>b)?1:((a<b)?-1:0); //Условно

}

void Sort(void)

{

qsort(list,count,sizeof(тип*),Cmp);

}

Ход работы

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

Задание 1

В задании необходимо разработать программу, в которой выполняется ввод списка записей определенного типа. Записи вводятся построчно в определенном формате, признак завершения ввода – ввод пустой строки. Список – двунаправленный. При написании программы реализовать функции: добавление элемента в конец списка, вставка элемента перед текущим элементом списка, удаление элемента из списка. При вводе данных записи упорядочиваются по определенному полю (согласно варианту задания). Направление упорядочивания на выбор разработчика. Полученный список вывести на экран. Варианты заданий:

Тип

Поле

Дополнительная

 

 

сортировки

обработка

1

char

-

Нет

2

int

-

Нет

3

unsigned

-

Нет

4

float

-

Нет

5

double

-

Нет

6

short

-

Нет

7

unsigned short

-

Нет

8

long long

-

 

 

Нет

 

9

unsigned long

-

 

 

Нет

 

long

 

 

 

 

 

 

 

 

 

10

long double

-

 

 

Нет

 

11

СТУДЕНТ

№ зач.

 

 

Нет

 

книжки

 

 

 

 

 

 

 

 

 

12

КНИГА

Название

 

 

Нет

 

13

МАШИНА

Марка

 

 

Нет

 

14

ФАЙЛ

Имя файла

 

 

Нет

 

15

СООБЩЕНИЕ

Номер

 

 

Нет

 

устройства

 

 

 

 

 

 

 

 

 

16

НАКЛАДНАЯ

ФИО

 

 

Нет

 

оператора

 

 

 

 

 

 

 

 

 

17

ФИРМА

Название

 

 

Нет

 

18

БИЛЕТ

Номер ряда

 

 

Нет

 

19

ПРОЦЕССОР

Порядковый

 

 

Нет

 

 

 

номер

 

 

 

 

20

САМОЛЕТ

Марка -

 

 

Нет

 

модель

 

 

 

 

 

 

 

 

 

 

 

 

Удалить

 

из

списка

21

СТУДЕНТ

ФИО

студентов,

родившихся

студента

позже

 

указанной

 

 

 

 

 

 

пользователем даты.

 

 

 

Удалить из списка книги,

22

КНИГА

ФИО автора

изданные

в

период,

 

 

 

заданный пользователем.

 

 

 

Удалить

 

из

списка

23

МАШИНА

Модель

машины, старше 10-ти

лет.

Текущий

год

 

 

 

 

 

 

указывает пользователь.

 

 

 

Удалить

 

 

файлы,

24

ФАЙЛ

Размер файла

созданные ранее даты и

времени,

указанных

 

 

 

пользователем.

 

 

 

 

Удалить

 

сообщения,

25

СООБЩЕНИЕ

Текст

полученные

после

сообщения

указанных пользователем

 

 

 

 

 

даты и времени.

 

 

 

 

Удалить

все накладные,

 

 

Номер

дата

 

которых

26

НАКЛАДНАЯ

предшествует

дате

накладной

 

 

введенной

 

 

 

 

 

 

 

 

 

 

пользователем.

 

 

 

 

Удалить

 

все

фирмы,

27

ФИРМА

ФИО

созданные

после дату,

владельца

указанной

 

 

 

 

 

 

 

 

 

пользователем.

 

 

 

 

Удалить все билеты, с

28

БИЛЕТ

Название

истекшей

 

датой.

сеанса

Текущую дату указывает

 

 

 

 

 

пользователь.

 

 

 

 

Удалить все процессоры,

 

 

Тактовая

тактовая

 

частота

29

ПРОЦЕССОР

которых,

не

лежит в

частота

 

 

диапазоне

указанном

 

 

 

 

 

 

пользователем.

 

 

 

 

Удалить все самолеты с

30

САМОЛЕТ

Серийный

числом

часов

налета

номер

более числа, указанного

 

 

 

 

 

пользователем.

 

СТУДЕНТ:

фамилия, имя, отчество (строки по 15 символов);

номер зачетной книжки (целое шестизначное число);

дата рождения (в формате дд.мм.гггг).

Формат ввода: Фамилия Имя Отчество [№ зачетной книжки], Дата рождения

КНИГА:

фамилия и инициалы автора (строка 15 символов);

название книги (строка 20 символов);

год издания (целое четырехзначное число);

количество страниц (целое десятизначное число).

Формат ввода: код ISBN: Фамилия И. О. «Название», год

МАШИНА:

марка (строка 15 символов);

модель (строка 5 символов);

серийный номер (целое семизначное число);

год выпуска (целое четырехзначное число).

Формат ввода: Марка Модель [Серийный номер], Год выпуска

ФАЙЛ:

имя файла (строка 30 символов, уникальное поле);

размер файла (целое число);

дата создания (в формате дд.мм.гггг);

время создания (в формате чч:мм).

Формат ввода: Имя файла, размер файла, дата и время создания

ПРОЦЕССОР:

производитель (строка 10 символов);

модель (строка 15 символов);

тактовая частота (целое число);

порядковый номер (целое десятизначное число в 16-ричной системе).

Формат ввода: Производитель Модель Тактовая частотаMHz Порядковый номер

САМОЛЕТ:

серийный номер (целое восьмизначное число)

марка - модель (строка 20 символов);

год выпуска (целое четырехзначное число);

время налета (целое число, в часах).

Формат ввода: Серийный номер Марка – модель, Год выпуска, Время начета

БИЛЕТ:

название сеанса (строка 30 символов);

дата и время сеанса (в формате дд.мм.гггг чч:мм);

номер ряда (целое число);

номер места (целое число).

Формат ввода: Номер «Название сеанса» Дата и время, Номер ряда, Номер места

СООБЩЕНИЕ:

номер устройства (целое трехзначное число)

ID сообщения (целое восьмизначно число в 16-ричной системе);

текст (строка 30 символов);

дата и время отправления (в формате дд.мм.гггг чч:мм).

Формат ввода: Номер устройства: ID сообщения «Текст» Дата и время отправления

НАКЛАДНАЯ:

номер накладной (целое число, уникальное поле);

дата накладной (в формате дд.мм.гггг);

общая сумма по накладной (вещественное число);

ФИО оператора (строка 20 символов).

Формат ввода: Номер: «Дата», Сумма, ФИО оператора

ФИРМА:

название (строка 20 символов);

УНН (целое десятизначное число, уникальное поле);

ФИО владельца (строка 20 символов);

дата основания (в формате дд.мм.гггг).

Формат ввода: Название [УНН], ФИО владельца, Дата основания

Соседние файлы в предмете Структуры и алгоритмы обработки данных