МУ_ЛР8_ОП (1079941), страница 4
Текст из файла (страница 4)
//Обратная адресация
D1.pPrev = NULL;
D2.pPrev = &D1;
D3.pPrev = &D2; // Последний ссылается на предпоследний …
My_DList.Count = 3;
Распечатка списка в цикле в обратном порядке для примера:
// Печать списка в обратном порядке для примера
printf ("Печать двунаправленного списка в обратном порядке: \n");
DElem * pWorkDE = My_DList.pTail ;
while ( pWorkDE != NULL)
{
printf (" Фам -> %s Курс -> %d Оклад -> %f \n", pWorkDE->pSTud->Name,
pWorkDE->pSTud->Num, pWorkDE->pSTud->Oklad );
pWorkDE = pWorkDE ->pPrev; // Навигация в обратном порядке
};
Добавление в голову в двунаправленном списке:
// Новый элемент для добавления в голову
DElem DHEAD = { NULL , NULL , NULL};
DHEAD.pSTud = (Student *) malloc ( sizeof(Student));
DHEAD.pSTud->Num = 5;
DHEAD.pSTud->Oklad = 50.0f;
strcpy( DHEAD.pSTud->Name,"ГОЛОВА");
// Добавление в голову (см. рисунок)
DHEAD.pNext = My_DList.pHead;
DHEAD.pPrev = NULL;
My_DList.pHead->pPrev = &DHEAD;
My_DList.pHead = &DHEAD;
My_DList.Count++;
Добавление в хвост в двунаправленном списке:
// Новый элемент для добавления в хвост
DElem DTAIL = { NULL , NULL , NULL};
DTAIL.pSTud = (Student *) malloc ( sizeof(Student));
DTAIL.pSTud->Num = 10;
DTAIL.pSTud->Oklad = 100.0f;
strcpy( DTAIL.pSTud->Name,"ХВОСТ");
//Добавление в хвост
DTAIL.pNext = NULL;
DTAIL.pPrev = My_DList.pTail;
My_DList.pTail->pNext = &DTAIL;
My_DList.pTail = &DTAIL;
My_DList.Count++;
Распечатка списка в цикле в прямом порядке:
// Распечатка
printf ("\nПечать двунаправленного списка после добавления в голову и хвост: \n");
pWorkDE = My_DList.pHead ;
while ( pWorkDE != NULL)
{
printf (" Фам -> %s Курс -> %d Оклад -> %f \n", pWorkDE->pSTud->Name,
pWorkDE->pSTud->Num, pWorkDE->pSTud->Oklad );
pWorkDE = pWorkDE ->pNext; // Навигация
};
Удаление из головы в двунаправленном списке:
// Удаление из головы
My_DList.pHead =My_DList.pHead->pNext;
My_DList.pHead->pPrev = NULL;
My_DList.Count--;
Удаление из хвоста в двунаправленном списке:
// Удаление из хвоста
My_DList.pTail = My_DList.pTail->pPrev;
My_DList.pTail ->pNext = NULL;
My_DList.Count--;
Распечатка списка в цикле в прямом порядке:
// Распечатка
printf ("\nПечать двунаправленного списка после удаления из головы и хвоста: \n");
pWorkDE = My_DList.pHead ;
while ( pWorkDE != NULL)
{
printf (" Фам -> %s Курс -> %d Оклад -> %f \n", pWorkDE->pSTud->Name,
pWorkDE->pSTud->Num, pWorkDE->pSTud->Oklad );
pWorkDE = pWorkDE ->pNext;
};
Очистка списка двунаправленного статического списка
// Очистка списка
My_DList.pHead= NULL;
My_DList.pTail= NULL;
My_DList.Count = 0;
Результаты работы фрагмента программы с двунаправленным списком:
Печать двунаправленного списка в обратном порядке:
Фам -> Иванов Курс -> 3 Оклад -> 30.000000
Фам -> Сидоров Курс -> 2 Оклад -> 20.000000
Фам -> Петров Курс -> 1 Оклад -> 10.000000
Печать двунаправленного списка после добавления в голову и хвост:
Фам -> ГОЛОВА Курс -> 5 Оклад -> 50.000000
Фам -> Петров Курс -> 1 Оклад -> 10.000000
Фам -> Сидоров Курс -> 2 Оклад -> 20.000000
Фам -> Иванов Курс -> 3 Оклад -> 30.000000
Фам -> ХВОСТ Курс -> 10 Оклад -> 100.000000
Печать двунаправленного списка после удаления из головы и хвоста:
Фам -> Петров Курс -> 1 Оклад -> 10.000000
Фам -> Сидоров Курс -> 2 Оклад -> 20.000000
Фам -> Иванов Курс -> 3 Оклад -> 30.000000
Знакомство с выполнением операций для двунаправленного списка позволяет сделать вывод, что операции добавления и удаления выполняются более просто, в частности отсутствуют циклы для поиска хвоста списка (предыдущего элемента от хвоста), которые необходимы для выполнения операций с однонаправленными списками, проще выполнить распечатку списка в обратном порядке.
22 Примеры программы с использованием файлового ввода и вывода
Вторая часть задания, помимо первой связанной с изучением теоретического раздела заключается в том, чтобы испытать в проекте СИ уже отлаженные программы и фрагменты программ. Возможно, что, осваивая теоретическую часть работы, вы уже на компьютере проверили выполнение фрагментов текста и применения различных операторов и алгоритмов (из раздела 3), тогда вам будет проще продемонстрировать их работу преподавателю. В дополнение к примерам, расположенным выше нужно испытать и изучить примеры расположенные ниже. Эти действия желательно сделать в отладчике. В приложении также представлены интересные примеры по теме лабораторной работы.
Для этого нужно создать пустой проект в MS VS (Test_LR2), как описано выше, скопировать через буфер обмена в него текст данных примеров, отладить его и выполнить.
23 Примеры, описанные в теоретической части ЛР
Нужно внимательно изучить и проверить работу всех примеров из теоретической части ЛР. Эти примеры расположены выше. Все примеры можно скопировать в свой проект. Все эти задания выполняются обязательно, они не требуют дополнительной отладки и легко (через буфер обмена -Clipboard) переносятся в программу. Все фрагменты должны демонстрироваться преподавателю. В частности, в первой, теоретической части представлены следующие примеры:
-
Создание простейшего списка вручную.
-
Распечатка простейшего списка в цикле (FirstList).
-
Простейший динамический список (pDList).
-
Ручная работа с однонаправленным списком на основе элементов.
-
Ручная работа с однонаправленным списком на основе структуры (MY_List).
-
Ручное добавление и удаление в голову и хвост.
-
Распечатка однонаправленного списка с помощью функции.
-
Очистка статического и динамического списков.
-
Работа с динамическим списком (указатель - pList).
-
Работа с двунаправленным списком (My_DList).
Кроме этого ниже представлены примеры, которые могут быть полезными, в том числе и при выполнении контрольных заданий. Их тоже желательно изучить и проверить в программном проекте. Выполнение этих задач не обязательно.
24 Структуры данных для примеров с однонаправленными списками
Структуры данных для элемента списка (ListElem) и самого списка (List) представлены ниже. Они используются для всех примеров с однонаправленными списками.
// Элементы списка
struct ListElem{
ListElem * pNext; // адрес следующего элемента списка
int ListVal; // информация, содержащаяся в списке
};
// Структура списка
struct List {
ListElem Head; // Голова списка
ListElem Tail; // Хвост списка
int Count; // Счетчик элементов
};
25 Функции для работы с однонаправленным списком
Ниже приведены универсальные функции для работы с однонаправленными списками. Эти функции используются в примерах представленных в следующих разделах данных методических указаний.
// Добавление элементов в однонаправленный список (в голову)
void AddList( List * pL , ListElem * pE)
{
if (pL->Head.pNext == NULL) {pL->Head.pNext = pE; pL->Tail.pNext = pE;}
else
{
pE->pNext = pL->Head.pNext;
pL->Head.pNext = pE;
};
(pL->Count)++;
};
// Добавление элементов в однонаправленный список (в хвост)
void AddTailList( List * pL , ListElem * pE)
{
if (pL->Head.pNext == NULL) {pL->Head.pNext = pE; pL->Tail.pNext = pE;}
else
{
// Поиск хвоста списка
ListElem * pELast;
ListElem * pCurr;
pCurr = &(pL->Head) ;
// Цикл поиска хвоста
while ( pCurr->pNext != NULL )
{
pELast = pCurr;
pCurr = pCurr->pNext;
};
//
pELast->pNext = pCurr;
pCurr->pNext = pE;
pL->Tail.pNext = pE;
pE->pNext = NULL;
};
(pL->Count)++ ;
};
// Удаление элементов из однонаправленного списка (из головы)
void DelList( List * pL )
{
if (pL->Head.pNext == NULL) { return; }
else
{
ListElem * pE;
pE = pL->Head.pNext ;
pL->Head.pNext = pL->Head.pNext->pNext;
pE->pNext = NULL;
if (pL->Head.pNext == NULL) { pL->Tail.pNext = NULL; };
(pL->Count)--;
}; };
// Удаление элементов из однонаправленного списка (из хвоста)
void DelLastList( List * pL )
{
if (pL->Head.pNext == NULL) return ;
// Цикл поиска хвоста списка
ListElem * pE;
ListElem * pTemp;
ListElem * pELast;
// Один элемент в списке
if (pL->Head.pNext->pNext == NULL) { pL->Head.pNext = NULL ;
pL->Tail.pNext = NULL;
pL->Count = NULL;return ; } ;
pTemp = &(pL->Head) ;
pE = pL->Head.pNext ;
// Поиск хвоста
while ( pE->pNext != NULL )
{
pELast = pE;
pTemp = pTemp->pNext;
pE = pE->pNext;
};
// Найден конец списка и главное предыдущийперед концом
pELast->pNext = NULL;
pL->Tail.pNext = pELast;
pTemp->pNext = NULL;
(pL->Count)-- ;
//
};
// Печать списка
void PrintList( List L)
{
if (L.Head.pNext == NULL) {
printf ("Список List пуст! \n");
return;};
printf ("Печать списка List(Счетчик = %d): \n", L.Count);
ListElem * pE = L.Head.pNext ;
while ( pE != 0)
{
printf ("Элемент = %d \n", pE->ListVal );
pE = pE->pNext; // Очень важно - навигация по списку
};
};
26 Функции вставки и удаления по номеру в однонаправленном списке
Ниже приведены универсальные функции для работы с однонаправленными списками. Эти функции могут использованы для добавления и удаления элемента по номеру, что в общем не очень характерно для списковых структур данных.
// Добавление по номеру (номером непосредственно) Нумерация с нуля
void AddListNum( List * pL , ListElem * pE , int Num)
{
//
if ( Num <= NULL) {AddList( pL , pE ); return;}// В голову
if ( Num >= pL->Count ) { AddTailList( pL , pE); return;}// В хвост
// Добавить в середину Num > 0 и Num < Count
// Найти указатель заданного номера
ListElem * pTemp = pL->Head.pNext;
int nCur ;
for ( nCur= 1 ; nCur < Num ; nCur++ )
pTemp = pTemp->pNext;
// Добавление
pE->pNext = pTemp->pNext;
pTemp->pNext = pE;
//Выход
return;
}
…
Фрагмент текста программы для добавления в список:
//ФУНКЦИИ ДОБАВЛЕНИЯ для однонаравленного списка
ListElem E55 = {NULL , 55};
ListElem E77 = {NULL , 77};
ListElem E99 = {NULL , 99};
AddList( &MY_List , &E55 ); // В голову
AddTailList ( &MY_List , &E77 ); // В хвост
AddListNum( &MY_List , &E99 ,3 ); // По номеру 3 с нуля (0 - 1 - 2 -3)
PrintElemList ( *(MY_List.Head.pNext) );
…
Результаты работы программы.
Печать списка элементов:
Элемент = 55
Элемент = 1
Элемент = 2
Элемент = 99
Элемент = 3
Элемент = 77
Функция для удаления элемента из списка:
//Удаление из списка по номеру
void DelListNum( List * pL , int Num)
{
// Проверка на правильность номера для удаления
if (( Num < NULL) || ( Num > pL->Count)) return; // Нет удаления
// Проверка на первый и последний
if ( Num <= NULL) {DelList( pL ); return;}// В голову
if ( Num >= pL->Count ) { DelLastList( pL ); return;}// В хвост
// Удалить в середину Num > 0 и Num < Count
// Найти указатель заданного номера
ListElem * pTemp = pL->Head.pNext;
int nCur ;
for ( nCur = 1 ; nCur < Num ; nCur++ )
pTemp = pTemp->pNext;














