Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DSD_Spiskovye_struktury_dannykh_na_baze_massivo...doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.59 Mб
Скачать

1.1.10Операции со списками в динамических массивах нетипизированных указателей

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

Тексты основных процедур будут иметь вид:

//------- расширение массива указателей ----- //

void ExpendArrPtr (void* &PtrArPtr, int &SizeAr, int Cnt)

/*увеличение размера массива указателей*/

{

int SizeW;

void* PtrArPtrW; /*вспомогательный бестиповый указатель на начало

массива указателей*/

SizeW = SizeAr; /*сохранение старого размера массива*/

SizeAr = SizeAr + Delta; /*определение нового размера массива*/

PtrArPtrW = PtrArPtr; /*сохранение указателя на старый массив*/

PtrArPtr = new void*[SizeAr]; /*выделение места для нового массива*/

/*копирование старого массива индексов в новый массив*/

for (int J = 0; J <=Cnt - 1; J++)

{

((void**)PtrArPtr)[J] = ((void**)PtrArPtrW)[J];

}

delete [ ] PtrArPtrW; /*удаление ста-рого массива*/

} /*ExpendArrPtr*/

//-------- Вывод списка в ListView -------------//

void PrintListInListView(void* PtrArrPtr, int count, System:: Windows:: Forms:: ListView * listView)

{

listView->Items->Clear();

if (count == 0) return;

for(int I = 0; I < count; i++)

{

listView->Items->Add(((TElmList*)(((void**)PtrArrPtr )[i]))->Name);

listView->Items->Item[i]->SubItems->Add(((TElmList*)(((void**)PtrArrPtr )[i]))->Address);

}

}

// ------------ Быстрый поиск ------------------- //

void FindElList2 (void* PtrArrPtr, int Cnt, char *Key, int &PosFndEl, bool &FindOK)

/*Поиск выполняется методом половинного деления*/

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

{

int Middl; /*Middl выступает как средняя граница обрабатываемой части

массива*/

int Hi,Low; /*текущие границы - верхняя, нижняя*/

FindOK = false; /*элемент не найден*/

if (Cnt == 0)

{

PosFndEl = 0;

return;

}

Low = 0;

Hi = Cnt - 1;

do

{

Middl = (Hi - Low) / 2 + Low; /* Middl = (Hi + Low) / 2 */

switch (strcmp(((TElmList*)((( void** )PtrArrPtr)[Middl]))->Name, Key))

{

case 0: PosFndEl = Middl; /*Элемент найден*/

FindOK = true; /*элемент найден*/

return;

case 1: Hi = Middl - 1;

break;

case -1:Low = Middl + 1;

break;

}

} while (Low <= Hi);

PosFndEl = Low; /*Перебран весь массив. Искомый элемент не найден. Оп

ределена позиция возможной вставки нового эле-мента*/

} /*FindElList2*/

// -------- Добавление в отсортированный список ---//

void AddElSortList(void* PtrArrPtr, int &Cnt, void* NewP,int PosAddEl)

{

if (PosAddEl == Cnt)

{

((void**)PtrArrPtr)[PosAddEl] = NewP;

}

else

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

for (int K = Cnt-1; K >= PosAddEl; K--) /*смещение на одну позицию вниз*/

{

((void**)PtrArrPtr)[K+1] = ((void**)PtrArrPtr)[K];

}

((void**)PtrArrPtr)[PosAddEl] = NewP;

}

Cnt++;

return ;

} /*AddElSortList*/

//--------- Удаление элемента -----------//

void DelElList (void* PtrArrPtr, int &Cnt, int PosDelEl)

{

if (Cnt == 0)

{ /*Список пуст*/

return;

}

/*по окончании поиска месторасположения удаляемого элемента в

списке - имеющего позицию PosDelEl}

/*удаление элемента списка*/

delete ((void**)PtrArrPtr)[PosDelEl];

/*возможная корректировка содержимого списка указателей*/

if (PosDelEl != Cnt - 1)

{

/*удаляемый элемент внутри списка*/

for (int K = PosDelEl+1; K <= Cnt - 1; K++)

{

/*смещение на одну позицию вниз*/

((void**)PtrArrPtr)[K-1] = ((void**)PtrArrPtr)[K];

}

}

Cnt--;

} /*DelElList*/

//-------- Удаление списка --------//

void DelList (void* &PtrArPtr, int &Cnt, int &SizeAr)

/*Удаление списка сводится к поочередному удалению всех эле-ментов списка. По окончанию удаления списка счетчик его элементов равен 0. Таким образом, удаляются только элементы списка, а массив указателей на элементы списка сохраняется для возможного после-дующего наращивания списка. Размер SizeArr массива указателей со-кращается до начального размера SizeArrH. Для полной очистки памяти от списка вслед за вызовом этой процедуры необходимо удалить массив указателей*/

{

if (Cnt != 0) /*список не пуст*/

{

/*удаление всех элементов внутри списка*/

for (int K = 0; K <= Cnt - 1; K++)

{

delete ((void**)PtrArPtr) [K];

}

Cnt = 0; /*сброс счетчика элементов списка в 0*/

/*сокращение размера массива указателей от SizeArr до

SizeArrH*/

/*освобождение места, занимаемого старым массивом*/

delete [ ] PtrArPtr;

/*выделение места для нового массива*/

PtrArPtr = new void*[SizeArrH];

SizeAr = SizeArrH;

}

} /*DelList*/

Рассмотрим общую схему работы с динамическими списками на основе динамических массивов.

Примечание. Данные об элементе списка вводятся в компонент textbox. Свойство Text данного компонента содержит строку ввода и имеет тип System::String*, а строковое поле элемента списка объявлено как массив символов (например, char [30]). Для перевода значения типа System::String* в char* воспользуемся дополнительной функцией

char* SystemStringToChar(System::String * string)

char* SystemStringToChar(System::String * string)

{

return (char*) (void*) System:: Runtime:: InteropServices:: Marshal:: StringToHGlobalAnsi(string);

}

Кнопка – создание списка. Массив динамический, создание списка состоит в инициализации переменной Count, которая содержит количество элементов списка, переменной SizeArr, которая содержит текущий размер массива и выделении участка памяти для массива указателей размером SizeAr.

// ------ Создать список -------------//

void Form1::btn_Create_Click(System::Object * sender, System::EventArgs * e)

{

Count = 0; /*Пока список пуст – количество элементов - 0*/

SizeArr = SizeArrH; /*Устанавливаем начальный размер массива*/

PtrDynArrPtr = new void* [SizeArrH]; /*выделяем место для массива*/

}

Занесение нового элемента списка. Осуществляется по нажатию кнопки «Добавить»на главной форме. Для ввода полей нового элемента создана дополнительная форма FAdd, которая содержит компоненты textBox для ввода и кнопку «+» для подтверждения окончания ввода информации о новом элементе.

Рисунок 1.16 - Дополнительная форма для ввода информации о новом элементе.

Для кнопки "+" на дополнительной форме необходимо установить свойству DialogResult значение OK для того чтобы по окончании ввода информации можно было проанализировать – чем закончился диалог с пользователем – нажатием кнопки "+" или нжатием кнопки Выход.

Рисунок 1.17 - Установка свойства DialogResult для кнопки "+"

// ------------ Добавить новый элемент ------------ //

void Form1::btnAdd_Click(System::Object * sender, System::EventArgs * e)

{

FormAdd *FAdd = new FormAdd(); /*создание дополнительной формы*/

/*Вызов дополнительной формы*/

/*Если на дополнительной форме бйла нажата кнопка «Добавить»,

то DialogResult формы будет иметь значение OK */

if (FAdd->ShowDialog() == DialogResult::OK)

{

/*Выделяем память для нового элемента списка*/

void* NPtrElm =new TElmList;

/*Заполняем поля нового элемента из введенной на до

полнительной форме информации в компонентах textBox*/

((TElmList*)NPtrElm)->Age = Convert::ToInt32(FAdd->textBoxAge->Text);

strcpy(((TElmList*)NPtrElm)->Name, SystemStringToChar(FAdd-> textBoxName->Text));

strcpy(((TElmList*)NPtrElm)->Address, SystemStringToChar(FAdd-> textBoxAdres->Text));

int PosAdd;

bool FindOK;

/*Поиск позиции вставки нового элемента в массиве*/

FindElList2 (PtrDynArrPtr,Count, ((TElmList*)NPtrElm)->Name,

PosAdd, FindOK);

/*Если массив заполнен полностью, то расширение

массива*/

if (SizeArr == Count)

{

ExpendArrPtr (PtrDynArrPtr, SizeArr, Count);

}

/*Добавление нового элемента в список в позицию

PosAdd*/

AddElSortList (PtrDynArrPtr, Count, NPtrElm, PosAdd );

/*Вывод списка в listBox*/

PrintListInListView(PtrDynArrPtr, Count, listView1);

}

}

/*Поиск элемента по полю Name*/

void Form1::btnFindEl_Click(System::Object * sender, System::EventArgs * e)

{

int PosFndEl; /*позиция в массиве найденного элемента*/

bool FindOK; /*Результат поиска - true -найден,false-нет такого эле-

мента*/

char *Key=SystemStringToChar(textBoxFind->Text); /*Ключ поиска бе-

рем из компонента textBoxFind на главной форме*/

/*Вызов процедуры поиска элементов*/

FindElList2(PtrDynArrPtr, Count, Key, PosFndEl, FindOK);

if (FindOK) /*Если такой элемент есть в списке*/

{

/*Подготовка строки с информацией о найденном элементе для вывода на экран*/

char* findResult = SystemStringToChar(String::Concat(textBox1->

Text,S", адрес: ",((TElmList*)(((void**)PtrDynArrPtr )[PosFndEl]))-> Address));

/*Вывод в окно сообщения о найденном элементе на

экран*/

MessageBox(NULL, findResult, "Результат поиска", MB_OK);

}

else

{

MessageBox(NULL, "Элемент не найден", "Результат поиска", MB_OK);

}

}

/*Удаление элемента списка по полю Name*/

void Form1::btnDel_Click(System::Object * sender, System::EventArgs * e)

{

/*Ключ удаляемого элемента вводится в компонент textBoxDel

на главной форме*/

char * Key = SystemStringToChar(textBoxDel->Text);

int PosDel;

bool FindOK;

/*Поиск удаляемого элемента*/

FindElList2(PtrDynArrPtr, Count,Key, PosDel, FindOK);

if (FindOK == false) /*если элемент не найден*/

{ return; }

/*Удаление элемента из списка*/

DelElList (PtrDynArrPtr, Count, PosDel);

/*Вывод списка на экран*/

PrintListInListView(PtrDynArrPtr, Count, listView1);

}

/*Удаление всего списка */

void Form1::btnDelList_Click(System::Object * sender, System::EventArgs * e)

{

DelList (PtrDynArrPtr, Count, SizeArr);

PrintListInListView(PtrDynArrPtr, Count, listView1);

/*Перед выходом из программы необходимо полностью

очистить память от массива указателей*/

/*Если работа со списком будет продолжаться, то оператор

delete [] PtrDynArrPtr выполнять не нужно*/

delete [] PtrDynArrPtr;

}