Специальные модифицирующие операции

Операция Назначение
flst.unique() Удаляет из списка дубликаты
flst.unique(op) Удаляет из списка дубликаты, для которых op возвращает true
flst.splice_after(pos, flst1) Перемещает все элементы списка flst1 в список flst и размещает их сразу за позицией итератора pos
flst.splice_after(pos, flst1,pos1) Перемещает элемент, занимаю-щий позицию pos1 в списке flst1, в список flst и размещает его сразу за позицией итератора pos (списки flst и flst1 могут совпадать)
flst.splice_after(pos, flst1,beg1,end1) Перемещает все элементы из диапазона [beg1,end1) списка flst1 в flst после элемента, заданного итератором pos
flst.sort() Сортирует все элементы списка с помощью оператора <
flst.sort(op) Сортирует все элементы списка по критерию, заданному бинар-ным предикатом op
flst.merge(flst1) Сливает два отсортированных списка: вставляет все элементы списка flst1 в список flst с сохранением сортировки; список flst1 после этого пуст
flst.merge(flstl,op) Сливает два отсортированных списка: вставляет все элементы списка flst1 в список flst с сохранением сортировки по критерию op; список flst1 после этого пуст
flst.reverse() Изменяет порядок следования всех элементов на противо-положный

 

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

//Листинг 26.2

#include <forward_list>

#include <iostream>

#include <algorithm>

#include <iterator>

#include <string>

using namespace std;

void printLists(const string s,

const forward_list<int> & lst1,

const forward_list<int> & lst2)

{

cout << s << endl;

cout << " listl:";

copy(lst1.cbegin(), lst1.cend(),

ostream_iterator<int>(cout, " "));

cout << endl << " list2:";

copy(lst2.cbegin(), lst2.cend(),

ostream_iterator<int>(cout, " "));

cout << endl;

}

int main()

{

// создаем два однонаправленных списка

forward_list<int> listl = { 1, 2, 3, 4 };

forward_list<int> list2 = { 77, 88, 99 };

printLists("initial:", listl, list2);

// вставляем шесть новых элементов

//в начало однонаправленного списка list2

list2.insert_after(list2.before_begin(),

99);

list2.push_front(10);

list2.insert_after(list2.before_begin(),

{ 10, 11, 12, 13 });

printLists("6 new elems:", listl, list2);

//вставляем все элементы однонаправленного

//списка list2 в начало списка listl

listl.insert_after(listl.before_begin(),

list2.begin(),

list2.end());

printLists("list2 into listl:",

listl, list2);

// удаляем второй элемент и элементы,

// расположенные после элемента,

// имеющего значение 99

list2.erase_after(list2.begin());

list2.erase_after(find(list2.begin(),

list2.end(), 99),

list2.end());

printLists("delete 2nd and after 99:",

listl, list2);

// сортируем последовательный список listl,

// присваиваем его списку list2 и

// удаляем дубликаты

listl.sort();

list2 = listl;

list2.unique();

printLists("sorted and unique:",

listl, list2);

// объединяем упорядоченные списки

// в списке listl

listl.merge(list2);

printLists("merged:", listl, list2);

}

Результаты выполнения программы:

initial:

listl:1 2 3 4

list2:77 88 99

6 new elems:

listl:1 2 3 4

list2:10 11 12 13 10 99 77 88 99

list2 into listl:

listl:10 11 12 13 10 99 77 88 99 1 2 3 4

list2:10 11 12 13 10 99 77 88 99

delete 2nd and after 99:

listl:10 11 12 13 10 99 77 88 99 1 2 3 4

list2:10 12 13 10 99

sorted and unique:

listl:1 2 3 4 10 10 11 12 13 77 88 99 99

list2:1 2 3 4 10 11 12 13 77 88 99

merged:

listl:1 1 2 2 3 3 4 4 10 10 10 11 11 12 12 13 13 77 77 88 88 99 99 99

list2:

 

Рассмотрим задачу:

Создать следующие классы: класс студент с полями: фамилия и номер зачетной книжки; класс группа студентов.

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

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

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

Написать программу, демонстрирующую работу с данными классами.

Решение задачи:

По условию задачи в программе определены три класса: student, group и функциональный класс funct.

В классе student два поля-данных (name и num), два конструктора: без параметров и с двумя параметрами, методы доступа к полям класса. Для перегрузки операций помещения в поток и извлечения из потока используются дружественные функции.

В классе group одно поле - двунаправленный список, элементами которого являются объекты класса student (list<student>). При реализации методов добавления и сортировки используем методы класса list<student>. При реализации поиска и удаления используются методы класса list<student> и алгоритмы STL:

Алгоритм count_if():

difference_type count_if(Iterator beg,

Iterator end, UnaryPredicate op);

подсчитывает элементы в интервале [beg,end), для которых унарный предикат op возвращает значение true. Возвращаемое значение difference_type соответствует типу разности итераторов (как правило, long).

Алгоритм find_if():

Iterator find_if(Iterator beg,Iterator end,

UnaryPredicate op);

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

Операции помещения в поток и извлечения из потока реализованы как дружественные функции.

В функциональном классе funct два поля: mode и fam, два конструктора (первый - для инциализации поля mode, второй – для инициализации поля fam), перегруженная операция вызова функции: для задания критерия поиска - функция с одним параметром типа student, возвращающая булевское значение; для задания критерия сортировки - бинарный предикат, два параметра которого имеют тип student. По условию задачи для типа данных student должны быть определены два критерия сортировки: по фамилии и по номеру зачетки. В зависимости от значения поля mode в бинарном предикате выполняется сравнение либо по полю name (при mode=0), либо по полю num (при mode=1) двух объектов класса student, передаваемых как параметры функции. В реализации критерия поиска по фамилии используется поле fam, значение которого сравнивается со значением поля name передаваемого в качестве параметра объекта класса student.

В функции main() создается объект класса group и тестируются методы данного класса и перегруженные операции включения в поток и извлечения из потока.

//Листинг 26.3

#include <iostream>

#include<fstream>

#include <list>

#include<algorithm>

#include <cstring>

#include<iterator>

using namespace std;

 

//Класс студент

class student{

char name[20]; // фамилия студента

int num; //номер зачетной книжки

public:

//конструктор без параметров

student(){}

 

//конструктор с параметрами

student(char *fam, int nm){

strcpy_s(name, fam);

num = nm;

}

 

const char* getname()

{

return name;

}

int getnum()

{

return num;

}

//перегруженные функции помещения в поток

//и извлечения из потока

friend ostream& operator<<(ostream &stream,

student ob);

friend istream& operator>>(istream &stream,

student &ob);

};

 

ostream& operator<<(ostream &stream,

student ob)

{

stream << ob.name << "\t";

stream << ob.num << "\n";

return stream;

}

 

istream& operator>>(istream &stream,

student &ob)

{

stream >> ob.name;

stream >> ob.num;

return stream;

}

 

 

//функциональный класс

//с перегруженными операциями вызова функции

class funct

{

int mode;

char fam[30];

public:

//конструктор c умолчанием

funct(int a=0)

{

mode = a;

}

 

//конструктор с параметром

funct(char * s)

{

strcpy_s(fam, s);

}

 

//унарный предикат

//критерий поиска

//по фамилии для класса student

bool operator()(student a)

{

if (strcmp(fam, a.getname()) == 0)

return true;

return false;

}

 

//бинарный предикат

//с разными критериями сортировки

//для класса student

bool operator()(student a, student b)

{

//по фамилии

if (mode == 0){

if (strcmp(a.getname(), b.getname())<0)

return true;

return false;

}

//по номеру зачетки

if (mode == 1)

return a.getnum()<b.getnum();

}

 

};

 

//класс группа студентов

class group{

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

//контейнер двунаправленный список

list<student> l;

public:

 

//добавление объекта класса

//студент в конец списка

void dobav(student stud)

{

l.push_back(stud);

}

 

//сортировка по фамилии

void sortname()

{

funct sravn;

//Сортирует все элементы по критерию sravn

//при mode=0

l.sort(sravn);

}

 

//сортировка по номеру зачетки

void sortnum()

{

funct sravn(1);

//Сортирует все элементы по критерию sravn

// при mode=1

l.sort(sravn);

}

 

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

//студентов с данной фамилией

void find(char * fam)

{

//создаем итераторы для работы со списком

list<student>::iterator ptr, p;

funct poisk(fam);

//определяем сколько студентов

//имеют данную фамилию

int n = count_if(l.begin(),

l.end(), poisk);

if (n>0){

p = l.begin();

for (int i = 1; i <= n; i++)

{

ptr = find_if(p, l.end(), poisk);

cout << *ptr;

ptr++;

p = ptr;

}

}

else

cout << "Студентов с фамилией "

<< fam << " нет!" << endl;

}

 

//удаление из списка всех студентов

//с данной фамилией

void del(char * fam)

{

//создаем итераторы для работы со списком

list<student>::iterator ptr, p;

 

funct poisk(fam);

//определяем сколько студентов

//имеют данную фамилию

int n = count_if(l.begin(),

l.end(), poisk);

if (n>0){

p = l.begin();

for (int i = 1; i <= n; i++)

{

ptr = find_if(p, l.end(), poisk);

l.erase(ptr);

p = l.begin();

}

}

else

cout << "Студентов с фамилией "

<< fam << " нет!" << endl;

}

 

//перегруженная операция вставки в поток

friend ostream& operator<<(ostream& st,

group &o)

{

for (auto ptr = o.l.begin();

ptr!= o.l.end(); ++ptr)

st << *ptr;

return st;

}

 

//перегруженная операция

//извлечения из потока

friend istream& operator>>(istream& st,

group &o)

{

student ob;

st >> ob;

o.l.push_back(ob);

return st;

}

};

 

int main()

{

setlocale(LC_CTYPE, "Russian");

//создаем список

group ob;

 

//добавляем объекты класса student

// в конец списка

ob.dobav(student("Petrov", 128));

ob.dobav(student("Sidorov", 456));

ob.dobav(student("Antonov", 345));

ob.dobav(student("Petrov", 555));

cout << "Список группы:" << endl

<< ob << endl;

 

//сортировка списка группы по фамилиям

ob.sortname();

cout <<

"Список группы после сортировки по фамилии:"

<< endl << ob << endl;

 

//сортировка списка группы

//по номерам зачеток

ob.sortnum();

cout <<

"Список группы после сортировки по номеру зачетки:"

<< endl << ob << endl;

 

//поиск в списке группы студентов

//с данной фамилией

cout << "Введите фамилию для поиска:"

<< endl;

char temp[20];

cin >> temp;

ob.find(temp);

cout << endl;

 

//удаление из списка группы

//студентов с данной фамилией

ob.del(temp);

cout <<

"Список группы после удаления студентов с фамилией"

<< temp << ":"<< endl << ob << endl;

 

cout<<"Введите информацию о студенте с

клавиатуры:"<< endl;

cin >> ob;

cout <<

"Список группы после ввода с клавиатуры:"

<< endl << ob << endl;

return 0;

}

 

Результаты выполнения программы:

Список группы:

Petrov 128

Sidorov 456

Antonov 345

Petrov 555

 

Список группы после сортировки по фамилии:

Antonov 345

Petrov 128

Petrov 555

Sidorov 456

 

Список группы после сортировки по номеру зачетки:

Petrov 128

Antonov 345

Sidorov 456

Petrov 555

 

Введите фамилию для поиска:

Petrov

Petrov 128

Petrov 555

 

Список группы после удаления студентов с фамилией Petrov:

Antonov 345

Sidorov 456

 

Введите информацию о студенте с клавиатуры

Dedov 1234

 

Список группы после ввода с клавиатуры:

Antonov 345

Sidorov 456

Dedov 1234

 

Задание:

Создать классы согласно варианту.

В классе из пункта а) варианта перегрузить операции помещения и извлечения из потока.

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

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

При поиске осуществлять сохранение выбранных записей в контейнер - двунаправленный список.

Можно добавить другие методы.

Написать программу, демонстрирующую работу с данными классами.

Вариант 1

а) Класс аналогово-цифровой преобразователь (АЦП) содержит поля: название микросхемы, название фирмы производителя, тип АЦП, разрядность выходных данных, скорость преобразования аналогового сигнала в цифровую форму.

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

Вариант 2:

а) Класс цифро-аналоговый преобразователь (ЦАП) содержит поля: название микросхемы, название фирмы производителя, тип ЦАП, разрядность, максимальная частота дискретизации, динамический диапазон.

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

Вариант 3

а) Класс сигнал содержит поля: тип сигнала, длительность сигнала, динамический диапазон, ширина спектра сигнала.

б) Класс список сигналов. Поиск и сортировку выполнять по типу сигнала, длительности сигнала, ширине спектра сигнала.

Вариант 4

а) Класс файл содержит поля: каталог, имя файла, расширение, дата и время создания, атрибуты «только чтение», «скрытый», «системный», признак удаления, количество выделенных секторов (размер сектора принять равным 512 байт).

б) Класс список файлов. Поиск и сортировку выполнять по каталогу, дате создания, по признаку удаления.

Вариант 5

а) Класс модель компьютера содержит поля: код и название марки компьютера, тип процессора, частота работы процессора, объем оперативной памяти, объем жесткого диска, объем памяти видеокарты, стоимость компьютера в условных единицах и количество экземпляров, имеющихся в наличии.

б) Класс список моделей компьютера. Поиск и сортировку выполнять по типу процессора, объему ОЗУ, памяти жесткого диска.

Вариант 6

а) Класс звуковой формат содержит поля: название формата, расширение файла, квантование, частота дискретизации, число каналов, величина потоков данных с диска, степень сжатия.

б) Класс список звуковых форматов. Поиск и сортировку выполнять по названию формата, расширению файла, степени сжатия.

Вариант 7

а) Класс модем содержит поля: название марки модема, название фирмы производителя, тактовая частота сигнального процессора, объем оперативной памяти, количество портов ввода-вывода, потребляемая мощность.

б) Класс список модемов. Поиск и сортировку выполнять по названию марки модема, названию фирмы производителя, объему оперативной памяти.

Вариант 8

а) Класс кабель связи «витая пара» содержит поля: название фирмы производителя, число жил, тип конструкции экрана, материал изоляции, категория кабеля.

б) Класс список кабелей связи «витая пара». Поиск и сортировку выполнять по названию фирмы производителя, числу жил, категории кабеля.

Вариант 9

а) Класс волоконно-оптический кабель содержит поля: название фирмы производителя, материал изготовления сердцевины, диаметр сердцевины, показатель преломления сердцевины, показатель преломления оболочки.

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

Вариант 10

а) Класс коаксиальный кабель содержит поля: название фирмы производителя, волновое сопротивление, область использования, материал внутреннего проводника, материал изоляции.

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

Вариант 11

а) Класс микроконтроллер содержит поля: название модели; название фирмы производителя, разрядность ядра, объем ОЗУ, объем флеш-памяти, тактовая частота ядра.

б) Класс список микроконтроллеров. Поиск и сортировку выполнять по названию модели, названию фирмы производителя, разрядности ядра.

Вариант 12

а) Класс интернет-соединение содержит поля: название организации интернет-провайдера, вид соединения, скорость передачи данных, колебание сетевой задержки.

б) Класс список интернет-соединений. Поиск и сортировку выполнять по названию организации интернет-провайдера, виду соединения, скорости передачи данных.

Вариант 13

а) Класс пассивный элемент электрических цепей содержит поля: название элемента, сопротивление, емкость, индуктивность.

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

Вариант 14

а) Класс гармонический сигнал содержит поля: фаза, амплитуда, частота.

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

Вариант 15

а) Класс система связи содержит поля: название, тип связи, скорость передачи данных.

б) Класс список систем связи. Поиск и сортировку выполнять по названию, типу связи, скорости передачи данных.


Практическое занятие 3. Ассоциативные контейнеры: множество и мультимножество

Множество (set) и мультимножество (multiset) – это ассоциативные контейнеры. Элементы в этих контейнерах хранятся отсортированными. Чтобы использовать множество или мультимножество в программе, необходимо включить в нее заголовочный файл <set>. Они отличаются только тем, что мультимножества могут содержать дубликаты, а множества — нет (рис. 27.1.).

 

Множество Мультимножество

 

Рис. 27.1. Множество и мультимножество

 

Типы множества и мультимножества определяются как шаблоны классов в пространстве имен std:

namespace std {

template <class Т,class Compare = less<T>,

class Allocator = allocator< T > >

class set;

 

template <class T, class Compare =less<T>,

class Allocator = allocator<T> >

class multiset;

}

Элементы множества или мультимножества относятся к произвольному типу Т, поддерживающему присваивание, копирование и сравнение по критерию сортировки. Необязательный второй параметр шаблона определяет критерий сортировки. По умолчанию используется критерий less. Объект функции less сортирует элементы, сравнивая их оператором <. Необязательный третий параметр шаблона определяет модель памяти. По умолчанию используется модель allocator, определенная в стандартной библиотеке С++.

Сравнение элементов при упорядочении осуществляется в соответствии с заданным критерием. Критерий сравнения должен определять строгое слабое упорядочение (strict weak orderning), определяемое следующими четырьмя свойствами:

1. Антисимметричностью.

Для оператора < это значит, что если выражение x < y имеет значение true, то выражение y < x имеет значение false. Для предиката pred() это значит, что если выражение pred(x, y) имеет значение true, то выражение pred(y, x) имеет значение false.

2. Транзитивностью.

Для оператора < это значит, что если выражение x < y равно true и значение выражения y < z равно true, то значение выражения x < z равно true. Для предиката pred() это значит, что если выражение pred(x, y) равно true и значение выражения pred(y, z) равно true, то значение выражения pred(x, z) равно true.

3. Иррефлексивностью.

Для оператора < это значит, что значение выражения x < x всегда равно false. Для предиката pred() это значит, что значение выражения pred(x, x) всегда равно false.

4. Транзитивностью эквивалентности (tratsitivity of equivalence), которое, грубо говоря, означает следующее: если объект a эквивалентен объекту b, а объект b эквива­лентен объекту c, то объект а эквивалентен объекту c.

Для оператора < это значит, что если значение выражения !(a < b) &&!(b < a) равно true и значение выражения !(b < c) &&!(c < b) равно true, то значение выражения !(a < c) &&!(c < a) равно true. Для предиката pred() это означает, что если значения выражений pred(a, b), pred(b, a), pred(b, c) и pred(c, b) равны false, то значения выражений pred(a, c) и pred(c, a) равны false.

Это значит, что следует различать отношения «меньше» и «равно». Оператор <= не удовлетворяет этому требованию.

Основываясь на этих требованиях, можно использовать критерий ссравнения и для проверки эквивалентности. Иначе говоря, два элемента считаются дубликатами, если ни один из них не меньше другого (оба выражения a < b и b < a равны false или и pred(x, y), и pred(y, x) равны false).

Для мультимножеств порядок эквивалентных элементов является случайным, но устойчивым. Таким образом, вставки и удаление сохраняют относительный порядок сле­дования эквивалентных элементов (это гарантируется стандартом С++11).

Множества set и мультимножества multiset в STL реализуются в виде сбалансированных красно-чёрных деревьев.

Операции с множествами и мультимножествами рассмотрим по группам (табл. 27.1 – 27.6).

 

Таблица 27.1


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: