Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование 3.docx
Скачиваний:
9
Добавлен:
17.11.2019
Размер:
265.13 Кб
Скачать

Лабораторная работа № 12 списки. Класс списка структур

  1. ЦЕЛЬ И ЗАДАЧИ РАБОТЫ

Целью работы является приобретение студентами навыков работы со списками.

Задачами работы являются:

  • написание программы на языке C++ с использованием класса списка структур;

  • добавление и удаление элементов списка;

  • обработка файловой информации;

  • создание меню программы;

  • осуществление процедуры поиска необходимых данных в классе списков структур и вывод результатов на экран и в файл;

  • тестирование работоспособности программы для различных исходных данных.

  1. КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

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

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

{ Data d; // информационная часть узла

// тип данных Data должен быть определен ранее

Node *next; // адресная часть узла

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

Над списками можно выполнять следующие операции:

  • добавление элемента в конец списка;

  • удаление элемента из списка;

  • начальное формирование списка;

  • просмотр (вывод) списка.

В качестве примера рассмотрим вариант задачи из лабораторной работы № 9, но теперь решим её с использованием класса списка структур.

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

Фамилия и инициалы

Курс

Группа

1

Иванов А. А.

1

ИСТ-101

2

Сидоров Б.Б.

1

САПР-120

...

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

  • include <iostream.h>

  • include <fstream.h>

  • include <string.h>

  • include <iomanip.h>

  • include <stdlib.h>

  • include <conio.h> struct student

{

char name[30]; int kurs; char gr[7];

};

// узлы первого списка

struct group {

char gr[7]; intng;

};

struct nodel {

student s; nodel*next;

};

struct node2 {

group g; node2*next;

};

// информационная часть узла первого списка // адресная часть узла первого списка

// узлы второго списка

// информационная часть узла второго списка // адресная часть второго узла

// класс списка структур

class spisok {

private:

nodel*begl, *endl; //указатели на начало и конец 1-го списка int п; //количество элементов в первом списке

node2 *beg2, *end2; //указатели на начало и конец 2-го списка int к; //количество элементов во втором списке

nodel*findname (student t); // нахождение узла 1-го списка public:

spisokO {m=k=0; begl =end 1 =beg2=end2=NULL;} //конструктор ~spisok(); //деструктор

void inputstudentfileO; // ввод из файла первого списка void outputstudent(); // вывод на экран первого списка

/

void addstudent(); void deletestudentO; void perechgroup(); void outputgroup(); void outputgroupfile();

/ добавление элемента в первый список // удаление элемента из первого списка //формирование второго перечня групп // вывод на экран второго списка // вывод в файл второго списка

// Определение деструктора spisok::~spisok ()

{

n

// указатель на узлы первого списка // указатель на узлы второго списка // если первый список не пустой // надо вернуть память, занимаемую им

odel *pl; node2 *р2; if (begl !=NULL)

{

while (begl!=NULL)

{ pl=begl; begl=begl->next;// узел удален из списка

/

delete pi;

/ освобождена память, занимаемая узлом

}

endl=NULL;

п=0;

}

if(beg2!=NULL)

{while (beg2!=NULL) { p2=beg2; beg2=beg2->next;

// второй список не пустой

// надо вернуть память, занимаемую им

// узел удален из списка

delete р2; // освобождена память, занимаемая узлом

}

end2=NULL;

k=0;

}

}

// Нахождение узла первого списка по заданной фамилии и группе nodel *spisok:: findname (student tt)

{

nodel *p; p=begl;

while (p!=NULL)

{if( strcmp( tt.name, p->s.name)=0 && strcmp( tt.gr, p->s.gr)=0) break;

// узел найден p=p->next;

}

return NULL; //узел не найден

II Ввод 1-ого списка (исходной таблицы задолжников) из файла void spisok:: inputstudentfile()

{

i

// рабочая переменная для инициалов // указатели на узлы первого списка // указатель на узлы второго списка ( 1-ого и 2-ого списков)

// первый список не пустой

// надо вернуть память, занимаемую им

fstream fin; char file[10]; char iniz[7]; nodel *pl, *p; node2 *p2;

// очистка рабочих областей if (begl !=NULL)

{ while (begl !=NTJLL)

{

pl=begl;

beg 1 =beg 1 ->next; // узел удален из списка

delete pi; // освобождена память, занимаемая узлом

}

endl=NULL;

п=0;

}

if (beg2!=NULL) // второй список не пустой

{ while (beg2!=NULL) // надо вернуть память, занимаемую им {

p2=beg2;

beg2=beg2->next; // узел удален из списка

delete р2; // освобождена память, занимаемая узлом

}

end2=NULL;

k=0;

}

// ввод 1-ого списка (таблицы задолжников) из файла cout« "Имя файла:” ; cin » file; fin.open(file);

if( fin—NULL) {соиК<”Файл не открыт.\п”; exit(l);}

p= new node 1; // выделение памяти для 1 -ого узла

if( p=NULL)

{cout«”Her динамической памяти.”;getchO; exit(l);} fin » p->s.name » iniz » p->s.kurs » p->s.gr;

strcat( p->s.name, “ “); // добавление инициалов через

strcat( p->s.name, iniz); // пробел к фамилии

p->next=NULL; while( fin.good())

{// Добавление нового узла в список if (begl=NULL) begl=p;

else endl->next=p; endl=p; n++;

// Формирование нового узла p= new nodel; if(p=NULL)

{cout«”HeT динамической памяти”; getch(); exit(l);} fin » p->s.name » iniz » p->s.kurs » p->s.gr ; strcat( p->s.name, “ “); // добавление инициалов через strcat( p->s.name, iniz); // пробел к фамилии p->next=NULL;

}

delete p; // удаление последнего несформированного узла fin.close();

}

// Вывод 1-го списка (таблицы задолжников) на экран void spisok:: outputgroupstudentO {

nodel *p;

cout« ” Исходный список структур. \n” ; cout« “Фамилия и инициалы Курс Группа \п”; for( p=begl; p!=NULL; p=p->next)

{cout«setw( 16)«p->s.name; cout«setw(7)«p->s.kurs«setw(8)«p->s.gr;}

}

// Добавление записи в 1-ый список (таблицу задолжников) void spisok:: addstudent()

{

nodel *p; // указатель для нового узла

char iniz[7]; // рабочая переменная для инициалов

// выделение памяти для нового узла р= new nodel;

if( p=NULL ) { cout«”Her динамической памяти.”; getch(); exit(l);

}

// ввод информации о добавляемом и формирование нового узла cout« “Введите фамилию: ”; cin » p->s.name » iniz;

strcat( p->s.name, “ “); // добавление инициалов через

strcat( p->s.name, iniz); // пробел к фамилии

cout« “Курс: ”;

cin» p->s.kurs;

cout« “Группа: ”;

cin» p->s.gr;

p->next=NULL;

// добавление нового узла в список if (beg 1 =NULL) beg 1 ==p; else endl->next=p; endl=p; n++;

}

// Удаление узла из первого списка void spisok:: deletestudent()

{

nodel *p, *p0;

student t; // рабочая переменная для информации об удаляемом

char iniz[7]; // рабочая переменная для инициалов

// ввод фамилии и группы удаляемого

cout« “Введите фамилию: ”;

cin»t.name» iniz;

strcat( t.name, “ “); // добавление инициалов через

strcat( t.name, iniz); // пробел к фамилии

cout« “Группа: ”; cin »t.gr; pO=findname(t);

if (pO=NULL) {cout«t.name<” не найден. \n“; getch(); return;}

if (pO=begl) //найденный узел является первым в списке

{

begl=begl->next; // удаление узла из списка

if (pO=endl) endl ==NULL; // узел последний в списке

}

else

{// поиск предшествующего узла p=begl;

while (p->next!=pO) p=p->next;

p->next=pO->next; // удаление узла из списка

if (pO=end 1) end 1 =p; //узел последний в списке

}

п—;

delete рО;

}

// Формирование второго списка (перечня групп) void spisok:: perechengroup()

{

int fl;

nodel *pl // указатель на узлы первого списка

node2 *р2, *р; // указатели на узлы второго списка

// очистка рабочей области (2-ого списка) if (beg2!=NULL) // второй список не пустой

{ while (beg2!=NULL) // надо вернуть память, занимаемую им {p2=beg2;

beg2=beg2->next; // узел удален из списка

delete р2; // освобождена память, занимаемая узлом

}

end2=NULL;

k=0;

}

// формирование второго списка for( pl=begl; pi !=NULL; pl=pl->next)

{fl=i;

for( p2=beg2; p2!=NULL; p2=p2->next)

{

if (strcmp (p 1 ->s.gr, p2->g.gr)=0)

{fl=0;

p2->g.ng++;

break;

}

}

if(fl=l)

{

p=new node2;

if (p=NULL) {cout«”HeT памяти”; getch(); exit(l);}

p->next=NULL;

strcpy (p->g.gr, pl->s.gr);

p->g.ng=l;

// Добавление нового узла во второй список if (beg2==NULL) beg2=p;

else end2->next=p; end2=p; k++;

}

}

}

// Вывод 2-го списка (перечня групп, имеющих задолжников) на экран

void spisok:: outputgroupO

{

node2 *p;

cout« ” Перечень групп, имеющих задолжников. \n”; cout«“ Группа Кол-во \n”; for( p=beg2; p!=NULL; p=p->next)

cout« setw(8)« p->g.gr « setw(8)« p->g.ng « « endl;

}

// Вывод 2-го списка (перечня групп, имеющих задолжников) в файл void spisok:: outputgroupfileO

{

ofstream fout; char file[10]; node2 *p;

cout«’’Имя файла:”; cin » file;

fout.open(file);

if( !fout.good()) {соШ«”Файл не открытЛп”; exit(l);} for( p=beg2; p!=NULL; p=p->next) fout« setw(8)« p->g.gr « setw(8)« p->g.ng « « endl; fout.close();

}

// Текст основной программы: void main()

{

spisok a; // Объект класса spisok

intj;

while (1)

{

clrscr();

cout« “1. Ввод таблицы из файла. \n”; cout« “2. Вывод таблицы на экран. \п”; cout« “3. Добавление записи в таблицу. \п”; cout« “4. Удаление записи из таблицы. \п”; cout« “5. Формирование перечня групп. \п”; cout« “6. Вывод перечня групп на экран. \п”; cout« “7. Вьшод перечня групп в файл. \п”; cout« “8. Выход из программы. \п”; cout« “\п Ваш выбор (1-8) cin »j; switch(j)

{

case 1: a.inputstudentfile(); break;

case 2: a.outputstudent(); getch(); break;

case 3: a.addstudentQ; break;

case 4: a.deletestudentO; break;

case 5: a.perechengroup(); break;

case 6: a.outputgroup(); getch(); break;

case 7: a.outputgroupfile(); break;

case 8: cout« “Завершение рабоы.”; getch(); return;

default: соиК<“Ошибка. Повторите ввод”; getch();

}

}

  1. ПОРЯДОК ВЫПОЛНЕНИЯ ЛАБОРАТОРНОЙ РАБОТЫ

  1. Получение задания на лабораторную работу.

  2. Разработка алгоритма решения задачи.

  3. Составление программы на языке C++

  4. Отладка составленной программы

  5. Тестирование отлаженной программы

  6. Составление отчета о проделанной работе

  1. ТРЕБОВАНИЯ К ОФОРМЛЕНИЮ ОТЧЕТА

  1. Оформить титульный лист с указанием темы работы.

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

  3. Отобразить блок-схему алгоритма.

  4. Записать текст программы.

  5. Привести результаты тестирования программы

  6. Сформулировать вывод по проделанной работе.

  1. ВАРИАНТЫ ЗАДАНИЙ

Варианты заданий соответствуют заданиям лабораторной работы № 9. Для решения необходимо использовать классы списка структур, предусмотрев выполнение операций добавления и удаления записей в исходном массиве. Для демонстрации методов класса требуется реализовать программу меню.

  1. КРИТЕРИИ РЕЗУЛЬТАТИВНОСТИ ВЫПОЛНЕНИЯ РАБОТЫ

Критерии результативности выполнения работы совпадают с критериями, приведенными в лабораторной работе № 10.

  1. КОНТРОЛЬНЫЕ ВОПРОСЫ

1.

Что такое динамические данные?

2.

Что такое узел?

3.

Как выглядит объявление узла?

4.

Что такое список?

5.

В чем основные отличия списков от массивов?

6.

Как определяется начало списка?