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

Объектно-ориентированные связанные списки.

Связным списком называется связный набор элементов со связями, устанавливающими порядок следования объектов в списке. Первый элемент списка называют головой списка, последний — хвостом. Наиболее часто рассматривают односвязный список, в котором устанавливаются связи типа "Следующий", и двусвязный список со связями типа "Предыдущий‑Следующий". Доступ к элементам списка осуществляется посредством операций определения предыдущего и последующего элемента по уже известному (например, по голове или хвосту).

Для реализации концепции связанного списка необходимы все характеристики ООП.

Рассмотрим пример, создающий информационный список сотрудников.

Родительский класс nnr содержит сведения, общие для всех порождаемых классов-потомков (фамилия и имя сотрудника, должность, номер социальной страховки и стаж работы), они содержатся в разделе protected. Класс использует дружественный класс payroll_list:

class nnr

{

friend class payroll_list;

protected:

char lstname[20];

char fstname[15];

char job_title[30];

char sosial_sec[12];

int year_hired;

nnr *pointer;

nnr *next_link;

public:

nnr(…){…next_link=0;}

void send_info();

};

На основе класс nnr строятся классы-потомки, один из них salesperson:

class salesperson:publuc nnr

{

friend class payroll_list;

private:

float sales;

int comm_rate;

public:

salesperson(…):nnr(…){sales=…;}

void fill_sales(float d_sales)

{sales=d_sales;}

void fill_comm_rate(int d_rate)

{comm_rate=d_rate;}

void add_info(){pointer=this;}

void send_info()

{

nnr::send_info();

cout<<”sales ”<<sales<<endl;

cout<<”Commision ”<<comm_rate;

}

};

В этом классе добавляется два частных элемента ( общая продажа и процент комиссионных). Для выделения памяти для каждого дополнительного элемента связного списка в функции addinfo используется не операция динамического выделения памяти, а указатель на объект this .

Выходная информация о конкретном сотруднике является уникальной. Функция send_info выводит сначала общую информацию вызовом функции базового класса, а затем частную информацию.

В дружественном классе payroll_list содержатся средства для печати связанного списка, добавления и удаления записей в списке:

class payroll_list

{

private:

nnr *location;

public:

payroll_list(){location=0;}

void print_payroll_list();

void insert_employee(nnr *node);

void remove_employee(char *social_sec);

};

Рассмотрим функцию print_payroll_list(). Сначала в ней значение указателя на список присваиваивается переменной present . если указатель не нулевой, то в списке есть еще записи, которые передаются функции send_info(). Далее указатель смещается, и процесс повторяется:

void payroll_list::print_payroll_list()

{

nnr *present=location;

while(present!=0)

{

present_>send_info();

present=present_>next_link;

}

}

Переменная pointer содержит адрес памяти, где находится данный представитель класса. Это значение используется в функции insert_employee() для реализации связи между записями связного списка. При добавлении записи располагаются в алфавитном порядке по фамилиям сотрудников. Когда находится уже имеющаяся в списке фамилия (node_>lstname), большая, чем current_node_>lstname, то первый цикл заканчивается. Это стандартная процедура вставки в связанный список: указатель previous_node ссылается на запись, после которой вставляется новая запись, а current_node указывает на запись, которая будет следовать за вновь добавленной записью.

Когда точка вставки определена, программа создает новую связь или узел путем вызова функции node_>add_info(). Указатель current_node связывается с указателем next_link этого нового узла. Кроме того, проводится проверка на начало списка:

void payroll_list::insert_employee(nnr* node)

{

nnr *current_node=location;

nnr *previoise_node=0;

while(current_node!=0 &&

strcmp(current_node->lstrname,node->lstrname)<0 )

{

previous_node=current_node;

current_node=current_node->next_link;

}

node->add_info();

node->pointer->next_link=current_node;

if(previouse_node==0)

location=node->pointer;

else

previouse_node->next_link=node->pointer;

}

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

void payroll_list::remove_employee(char* social_sec)

{

nnr *current_node=location;

nnr *previoise_node=0;

while(current_node!=0 &&

strcmp(current_node->social_sec,social_sec)!=0 )

{

previous_node=current_node;

current_node=current_node->next_link;

}

if(current_node !=0 && previouse_node==0)

{

location=current_node->nex_link;

delete current_node;

}else

if(current_node !=0 && previouse_node!=0)

{

previouse_node->next_link=current_node->next_link;

delete current_node;

}

}

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