Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Задание С++ 07_10_08_.doc
Скачиваний:
25
Добавлен:
11.03.2016
Размер:
1.15 Mб
Скачать

Задание 3.4 Сравнение структур

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

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

int equal(Record* t, Record* r)

{ return ((r->autor[0] !=0)? !strcmp(r->autor,t->autor):1) &&

((r->title && r->title[0] !=0)? !strcmp(r->title, t->title) :1) &&

((r->price !=0)? r->price ==t->price :1) &&

((r->number !=0)? r->number==t->number :1)&&

((r->day !=0)? r->day==t->day :1)&&

((r->month !=0)? r->month==t->month :1)&&

((r->year !=0)? r->year==t->year :1);

}

Функция, сравнивающая записи, используется при сортировки .

Пример реализации функции, сравнивающей структуры по первым трем полям

int cmp(Record* r, Record* t)

{int cond;

if(t->autor[0]!=0 && (cond=strcmp(r->autor,t->autor))) return cond;

else if(t->title[0] !=0 &&(cond=strcmp(r->title, t->title)) ) return cond;

else return r->number-t->number;

}

Указатели на функции

Использавание одной функции сmp для сравнения записей обладает существенным недостатком. Для проведения поиска по другим полям необходимо изменять функцию сравнения и перекомпилировать код.

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

Кроме того, для поиска и сортировки необходимо использовать разные функции. При поиске в качестве критерия отбора необходимо использовать булевскую функцию, аргументом которой является один элемент (предикат первого порядка)., а для сортировки – булевскую функцию , определенную на паре элементов (предикат второго порядка). Более того, эти булевские функции могут содержать аргумент, через который передаются дополнительные параметры, например данные для поиска. Для того чтобы функции не зависили от типа данных можно тип параметра определить как vod*. В языке Си использование указателей на функции совместно с типомvod* является единственным средством построения полиморфных ,т.е. независящих от типа данных, програм . В языке С++ для этих целей применяется наследование классов и фиртуальные функции, а также шаблоны.

Поиск

Определим заголовок функции поиска следующим образом

T* find(Tabl* t,Pr fun=0 ,void* param=0, T*begin=0)

Для согласование с ранее разработанным интерфейсом используются параметры по умолчанию

Функция ищет по заданному условию запись в таблице T, начиная с элемента на который указываетbegin. Введение этого параметра позволяет осуществить поиск следующего элемента. Данные для поиска передаются через аргумент с именемparam.Параметр функцииfindс именемfun– это указатель на функцию, сравнивающую запись с параметрами поиска. Тип указателя нfфункцию определяется следующим образом

typedefbool(*Pr)(Record*,void*); строка добавляется в заголовочный файл

Использование указателя на функцию сравнения и задание параметров поиска в виде void* позволяет использовать одну и ту же функцию для различных условий поиска. В качестве второго параметра можно использовать любую структуру с данными для поиска. При реализации функций необходимо явное приведения указателяvoid* к типу указателя на структуру поиска.

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

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

bool EqualParam (Record*t, void*)

{ record*r=(Record*)r0;

return equal (t, r);

}

В другом примере в качестве параметра используется структура

struct InRange{

int MinValue,MaxValue;

};

bool InRangePrice(Record* item, void* param)

{InRange *p=(InRange *)param;

return (item->price-p->MinValue)>=0 && (item->price-p->MaxValue)<=0;

}

Cортировка

Определим заголовок функции сортировки следующим образом

void sort(Tabl* t,Cmp fun=0,void* param=0);

Параметр функции с именем fun– это указатель на функцию, сравнивающую два элемента. Тип указателя на функцию определяется следующим образом

typedefbool(*Cmp)(constT&,constT&,void*param);

Примером такой функции может служить функция, сравнивающая записи по полю , имя которого передается через параметр

int CmpField(Record* a,Record* b,char*s)

{if (!strcmp(s,"autor")) return strcmp(a->autor,b->autor);

else if(!strcmp(s,"title")) return strcmp(a->title,b->title);

else if (!strcmp(s,"price")) return a->price-b->price;

else if (!strcmp(s,"number")) return a->number-b->number;

else if (!strcmp(s,"day")) return a->day-b->day;

else if (!strcmp(s,"month")) return a->month-b->month;

else if (!strcmp(s,"year")) return a->year-b->year;

}

При вызове функции sortнеобходимо использовать приведение типа.

Sort(t, (Cmp) FieldCmp,(void*)string);

В другом примере в качестве параметра используется структура

struct ParamSort {

char* FieldName[3];

int DirectCond[3];

};

Она позволяет задавать произвольные три поля для сравнения и направление сортировки (по возрастанию или по убыванию)

int CmpParam( Record* a, Record* b,void* param)

{ParamSort*p=(ParamSort*)param;

if(CmpField(a,b,p->FieldName[0])!=0)

if(p->DirectCond[0]==1) return CmpField(a,b,p->FieldName[0])>0;

else return CmpField(a,b,p->FieldName[0])<0;

else if(CmpField(a,b,p->FieldName[1])!=0)

if(p->DirectCond[1]==1) return CmpField(a,b,p->FieldName[1])>0;

else return CmpField(a,b,p->FieldName[1])<0;

else if(CmpField(a,b,p->FieldName[2])!=0)

if(p->DirectCond[2]==1) return CmpField(a,b,p->FieldName[2])>0;

else return CmpField(a,b,p->FieldName[2])<0;

}

Функции - элементы структур

Язык С++ позволяет использовать в качестве элементов структур функции. Это делает возможным объединить данные и обрабатывающие их функции в единое целое.

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

struct Predicate{

void* param;

Pr f;

bool fun( Record* item){return (*f)(item,param);}

};

int find( Tabl*t,int first,int last,Predicate &pred);

int remove(Tabl*t,Predicate &pred);

Изменения в реализации произойдут только в одной строке

int find( Tabl*t,int first,int last,Predicate &pred)

{T* i;

for(i=begin(t)+first;i!=begin(t)+last;i++)

if(pred.fun(*i)) return i-t->m;

return -1;

}

Аналогично для функции сортировки

struct Compare{

void* param;

Cmp f;

int cmp( Record* a, Record* b)

{return (*f)(a,b,param);}

};

void sort(Tabl*t,Compare &Comp );

Выполнение запросов.

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

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

Tabl* Query(Tabl*t, Predicate& pred)

{Tabl*rez=init(t,24);

T* i;

for( i= begin(t); i!=end(t);i++)

if(pred.fun(*i))

insert(rez,*i);

return rez;

}