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

5.3Пример 1

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

Этот пример иллюстрирует использование динамического массива нетипизированных указателей на элементы списка и использование указателей на функциии, передаваемых как параметр других функций.

Обращение к динамическому массиву нетипизированных указателей выполняется с помощью указателя PtrDynArrPtr. Первоначально в динамической памяти выделяется место под SizeArrPtrElmLst указателей на элементы списка. По мере необходимости размер массива увеличивается на величину Delta с помощью процедуры ExpenArrPtrElmLst.

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

Добавление элементов в список выполняется по принципу добавления в конец списка. Указатель на новый элемент списка добавляется за последним элементом массива указателей с помощью процедуры AddElEndList.

Упорядочивание элементов в списке выполняется путем сортировки месторасположения соответствующих указателей в массиве указателей. Для этого для простоты изложения используется процедура BubbleSortList, которая в качестве параметров получает указатель на массив указателей на элементы списка PtrDnArPtr, указатель на функцию сравнения PFuncComp и направление сортировки Direct. В действительности для упорядочивания больших массивов могут использоваться более производительные методы сортировки [12].

В качестве функции сравнения, передаваемой в процедуру BubbleSortList в качестве параметров, используется указатель на одну из двух функций CompTwoElmOnName и CompTwoElmOnAddress. Эти функции выполняют сравнение двух указанных элементов списка соответственно по полю Name или Address. В зависимости от результата сравнения функции возвращают значение из множества {-1, 0, 1}.

Поиск элемента в списке выполняется с помощью функции FindElSortList, которая в качестве параметров получает указатель на массив указателей на элементы списка PtrDnArPtr, функцию сравнения FuncComp и направление сортировки Direct.

В качестве функции сравнения, передаваемой в процедуру FindElSortList в качестве параметров, используется указатель на одну из двух функций CompNameAndKey и CompAddrAndKey. Эти функции выполняют сравнение указанного элемента списка соответственно по полю Name или Address с заданным ключом. В зависимости от результата сравнения функции возвращают значение из множества {-1, 0, 1}.

Удаление элемента из списка выполняется как расматривалось выше. А именно, с помощью функции DelElList, которая в качестве параметров получает указатель на массив указателей на элементы списка PtrDnArPtr, и позицию PosDelEl в этом массиве указателя на удаляемый элемент. Позиция указателя PosDelEl отыскивается с помощью процедуры FindElSortList.

Для работы с функциями сравнения вводится статический массив в динамической памяти из 4-х нетипизированных указателей на функции. Обращение к этому массиву выполняется с помощью указателя PtrArrPtrFunc. В качестве параметра функций BubbleSortList и FindElSortList используется указатель на эту функцию сравнения.

Текст программы имеет следующий вид:

const SizeArrH = 4; /*начальное значение верхней границы массива указателей

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

const Delta = 10; /*приращение размера массива указателей*/

const PosCnt = -1; /*индекс служебного элемента в массиве,

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

const PosSize= -2; /*индекс служебного элемента в массиве,

содержащего текущий размер массива*/

const Up = +1; /*сортировка по возрастанию*/

const Down = -1; /*сортировка по убыванию*/

typedef

struct ElmList

{

char Name[30];

int Age;

char Address[30];

} TElmList;

typedef

int (*TPFuncCompFieldOfTwoElmList) ( void*, void* ); /*тип указателя на

функцию*/

typedef

int (*TPFuncCompFieldElmListAndKey) (void*, char*); /*тип указателя на

функцию*/

// Объявление переменных

void* PtrArrPtrFunc; /*указатель на начало массива указателей на функции*/

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

int DirSort; /*направление сортировки списка*/

/*--Сравнение соответствующих полей двух элементов записи--*/

int CompTwoElmOnName (void* Elm1, void* Elm2)

{

//сравнение элементов по полю Name

return (strcmp( ((TElmList*)Elm1)->Name ,((TElmList*)Elm2)->Name ) );

} /*CompTwoElmOnName*/

int CompTwoElmOnAddress (void* Elm1, void* Elm2)

{

//сравнение элементов по полю Address

return (strcmp( ((TElmList*)Elm1)->Address , ((TElmList*)Elm2)->Address ) );

} /*CompTwoElmOnAddress*/

/*--Сравнение поля элемента записи и ключа--*/

int CompNameAndKey (void* Elm, char* KeyName)

{

return strcmp(((TElmList*)Elm)->Name, KeyName );

} /*CompNameAndKey*/

int CompAddrAndKey (void* Elm, char* KeyAddr)

{

return strcmp(((TElmList*)Elm)->Address, KeyAddr );

} /*CompAddrAndKey*/

// Создание массива указателей

void* CreateArrPtr(int PosCnt, int PosSize, int SizeArrH)

{

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

void* PtrArrPtr = new void* [SizeArrH+2];

/*формирование действующего указателя PtrArPtr в новом массиве указателей*/

PtrArrPtr= (void*) (((int)PtrArrPtr) + sizeof(int)*2);

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

((int*)PtrArrPtr)[PosCnt]=0;

/*сохранение начального размера массива*/

((int*)PtrArrPtr)[PosSize]=SizeArrH;

return PtrArrPtr;

}

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

void ExpendArrPtr (void* &PtrArPtr)

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

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

{

int SizeW;

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

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

SizeW = ((int*)PtrArPtr)[PosSize]; /*сохранение старого размера массива*/

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

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

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

PtrArPtr= (void*)(((int)PtrArPtr) + sizeof(int) * 2);

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

for (int J = 0; J <= ((int*)PtrArPtrW)[PosCnt] - 1; J++)

{

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

}

/*копирование реального количества элементов списка из старого

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

((int*)PtrArPtr)[PosCnt] = ((int*)PtrArPtrW)[PosCnt];

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

((int*)PtrArPtr)[PosSize] = SizeW + Delta + 2;

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

PtrArPtrW = (void*)(((int)PtrArPtrW) - sizeof(int) * 2);

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

} /*ExpendArrPtr*/

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

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

{

listView->Items->Clear();

int count = ((int*)PtrArrPtr)[PosCnt];

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);

}

} /* PrintListInListView */

/// -------- Добавление элемента в конец списка ---///

void AddElEndList(void* PtrArrPtr, void* NewP)

{

int cnt;

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

cnt=((int*)PtrArrPtr)[PosCnt];

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

((int*)PtrArrPtr)[PosCnt]=((int*)PtrArrPtr)[PosCnt]+1;

return ;

} /*AddElEndList*/

void BubbleSortList (void* PtrArrPtr, TPFuncCompFieldOfTwoElmList PFuncComp, int Direct)

/*Сортировка "пузырьком"*/

{

int i, j;

void* X;

int cnt;

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

cnt=((int*)PtrArrPtr)[PosCnt];

for (i=0; i<=cnt-2; i++)

{

for (j=0; j<=cnt-2-i; j++)

{

if (PFunComp(((void**)PtrArrPtr)[j],((void**)PtrArrPtr)[j+1])==Direct)

{

X = ((void**)PtrArrPtr)[j+1];

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

((void**)PtrArrPtr)[j] = X;

}

}

}

} /*BubbleSortList*/

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

void FindElList(void* PtrArrPtr, char *Key,TPFuncCompFieldElmListAndKey PFuncCmp, int Direct, int &PosFndEl, bool &FindOK)

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

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

{

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

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

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

if (((int*)PtrArrPtr)[PosCnt] == 0)

{

PosFndEl = 0;

return;

}

Low = 0;

Hi = ((int*)PtrArrPtr)[PosCnt] - 1;

do

{

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

if (PFuncCmp ( (( void** )PtrArrPtr )[Middl] , Key ) ==0)

{

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

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

return;

}

else

{

if (PFuncCmp((( void** )PtrArrPtr )[Middl],Key)==Direct)

Hi = Middl - 1;

else

Low = Middl + 1;

}

} while (Low <= Hi);

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

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

} /*FindElList*/

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

void DelElList (void* PtrArrPtr, int PosDelEl)

{

if (((int*)PtrArrPtr)[PosCnt] == 0)

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

return;

}

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

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

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

if (PosDelEl != ((int*)PtrArrPtr)[PosCnt] -1)

{

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

for (int K=PosDelEl+1; K <= ((int*)PtrArrPtr)[PosCnt]-1; K++)

{

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

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

}

}

((int*)PtrArrPtr)[PosCnt]=((int*)PtrArrPtr)[PosCnt]-1;

} /*DelElList*/

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

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

{

// Создание массива указателей

PtrDynArrPtr=CreateArrPtr(PosCnt , PosSize, SizeArrH);

//выделение места для массива указателей на функции

PtrArrPtrFunc = new void* [4];

//формирование массива указателей на функции

((void**)PtrArrPtrFunc) [0]= CompTwoElmOnName;

((void**)PtrArrPtrFunc) [1]= CompTwoElmOnAddress;

((void**)PtrArrPtrFunc) [2]= CompNameAndKey;

((void**)PtrArrPtrFunc) [3]= CompAddrAndKey;

} /* btn_Create_Click */

//-----Кнопка - Добавление нового элемента ----//

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

{

void* NPtrElm =new TElmList; //выделение места для нового элемента списка

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

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

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

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

if ( ((int*)PtrDynArrPtr)[PosSize]==((int*)PtrDynArrPtr)[PosCnt] )

{

//количество элементов списка совпадает с размером массива

ExpendArrPtr (PtrDynArrPtr); // расширение массива указателей

}

AddElEndList(PtrDynArrPtr, NPtrElm);

PrintListInListView(PtrDynArrPtr, listView);

} /* btnAdd_Click */

// --- РАБОТА С ПОЛЕМ Name --- //

// --- Кнопка – сортировка списка по полю Name --- //

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

{

DirSort = Up; /*Down*/ /*Установка направления сортировки*/

//сортировка по полю Name

BubbleSortList (PtrDynArrPtr, ((TPFuncCompFieldOfTwoElmList*) PtrArrPtrFunc) [0], DirSort);

//вывод списка после сортировки в ListView

PrintListInListView(PtrDynArrPtr, listView1);

} /*buttonSortName_Click*/

// --- Кнопка - удаление элемента для списка, отсортированного по полю Name //

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

{

// в textBox1 вводится имя для удаления

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

int PosDel;

bool FindOK;

FindElList (PtrDynArrPtr, Key, ((TPFuncCompFieldElmListAndKey*) PtrArrPtrFunc) [2] , DirSort, PosDel, FindOK);

if (FindOK == false) { return; }

DelElList (PtrDynArrPtr, PosDel);

PrintListInListView(PtrDynArrPtr, listView1);

} /* btnDel_Click */

// --- РАБОТА С ПОЛЕМ Address --- //

// --- Кнопка – сортировка списка по полю Address --- //

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

{

DirSort = Up; /*Down*/ /*Установка направления сортировки*/

//сортировка по полю Address

BubbleSortList (PtrDynArrPtr, ((TPFuncCompFieldOfTwoElmList*) PtrArrPtrFunc) [1], DirSort);

//вывод списка после сортировки в ListView

PrintListInListView(PtrDynArrPtr, listView1);

} /* buttonSortAddress_Click */

// --- Кнопка - удаление элемента для списка, отсортированного по полю Address //

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

{

// в textBox1 вводится адрес для удаления

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

int PosDel;

bool FindOK;

FindElList (PtrDynArrPtr, Key, ((TPFuncCompFieldElmListAndKey*) PtrArrPtrFunc) [3] , DirSort, PosDel, FindOK);

if (FindOK == false) { return; }

DelElList (PtrDynArrPtr, PosDel);

PrintListInListView(PtrDynArrPtr, listView1);

} /* btnDelAddress_Click */