МУ_ДЗ_2014 (1079920), страница 8
Текст из файла (страница 8)
};
После этого можно выполнить следующий фрагмент программы:
cout<< "Удаление по условию = Point(51,52) P2 (до):" << endl;
lP.insert( PIter, P2 );
Print_list(lP);
GP.x = 51; GP.y = 52;
lP.remove_if( is_XA<Point>( ) );
cout<< "Удаление по условию = Point(51,52) P2 (после):" << endl;
Print_list(lP);
Получим в результате
Удаление по условию = Point(51,52) P2 (до):
l[0] = { x = 51 y = 52 }
l[1] = { x = 51 y = 52 }
l[2] = { x = 31 y = 32 }
l[3] = { x = 1 y = 2 }
l[4] = { x = 1 y = 2 }
l[5] = { x = 51 y = 61 }
l[6] = { x = 51 y = 61 }
Удаление по условию = Point(51,52) P2 (после):
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 61 }
l[4] = { x = 51 y = 61 }
Функции sort требуют описания перегруженных операций сравнения (“>”,”<”) для объекта Point. Для упрощения предиката зададим сортировку только по параметру x. Например, дружественной функцией:
…
friend bool operator>(const Point & p1 , const Point & p2) ; // Описание в классе Point
friend bool operator<(const Point & p1 , const Point & p2) ; // Описание в классе Point
…
// Перегурузка операции “<” для сортировки (описание вне класса)
bool operator<(const Point & p1 , const Point & p2)
{
return ( p1.x < p2.x );
};
//
// Перегрузка операции “>”для сортировки
bool operator>(const Point & p1 , const Point & p2)
{
return ( p1.x > p2.x );
};
Пример использования метода sort показан ниже, всеемте со следующим. Используемый метод reverse позволяет изменить порядок расположения объектов на обратный порядок. После этого можно выполнить следующий фрагмент программы:
lP.push_front( *new Point(20 ,32) );
cout<< "Обратный порядок (до):" << endl;
Print_list(lP);
lP.reverse( ); // Изменение порядка на обратный
cout<< "Обратный порядок (после):" << endl;
Print_list(lP);
cout<< "Сортировка по возрастанию х:" << endl;
lP.sort( ); // По умолчанию less (меньше) – сортировка по возрастанию
Print_list(lP);
cout<< "Сортировка по убыванию х:" << endl;
lP.sort( greater<Point>( ) ); // здесь используются операции отношения и сортировка по
// убыванию greater
Print_list(lP);
Получим в результате:
Обратный порядок (до):
l[0] = { x = 20 y = 32 }
l[1] = { x = 31 y = 32 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 61 }
l[4] = { x = 51 y = 61 }
Обратный порядок (после):
l[0] = { x = 51 y = 61 }
l[1] = { x = 51 y = 61 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 31 y = 32 }
l[4] = { x = 20 y = 32 }
Сортировка по возрастанию х:
l[0] = { x = 1 y = 2 }
l[1] = { x = 20 y = 32 }
l[2] = { x = 31 y = 32 }
l[3] = { x = 51 y = 61 }
l[4] = { x = 51 y = 61 }
Сортировка по убыванию х:
l[0] = { x = 51 y = 61 }
l[1] = { x = 51 y = 61 }
l[2] = { x = 31 y = 32 }
l[3] = { x = 20 y = 32 }
l[4] = { x = 1 y = 2 }
Предлагаю сильным студентам разобраться с использованием других различных предикатов самостоятельно. Особенностью использования собственных объектов является необходимость перегрузки операций вывода. Другой особенностью класса list является автоматическое корректное удаление динамических объектов, созданных в программе и включенных в массив. В ЛР необходимо описать собственный класс объектов и продемонстрировать все возможности списков типа list.
48 Контейнерные классы списков в MFC
В библиотеке MFC (Microsoft Foundation Class) предусмотрено два основных класса для работы со списками: CList и CObList. Кроме этих классов предусмотрены классы для заданного типа включаемых объектов: CStringList, CPtrList. Класс CList является шаблонным, для создания объектов необходимо указать тип, а класс CObList не требует типизации, в него могут включаться любые объекты, наследованные от класса CObject. Методы первого и второго классов практически совпадают по названию и назначению. Рассмотрим первоначально класс CList. Для добавления в список используются различные методы: АddHead, AddTail, InsertAfter, InsertBefore и другие. Формально списки типа CList являются шаблонами вида:
template< class TYPE, class ARG_TYPE = const TYPE& >
class CList : public CObject { …};
Настройка конкретного объекта списка требует указания типа (например, int). Пример описания и добавления в список переменных типа int.
CList<int , int> IntList; // Список объектов целого типа
for (i = 0 ; i < 3 ; i++ )
IntList.AddTail(i);
POSITION pos;
cout << "Цикл вывода из списка !" << endl;
for( pos = IntList.GetHeadPosition(); pos != NULL ; )
{
cout << "IntList = " << IntList.GetAt(pos) << endl;
IntList.GetNext( pos); };
В результате получим:
Цикл вывода из списка !
IntList = 0
IntList = 1
IntList = 2
Методы GetHeadPosition и GetNext позволяют получить позицию начала списка и следующего элемента соответственно. Доступ к значению элемента списка производится с помощью метода GetAt. Метод GetAt позволяет получить значение элемента списка по позиции, позицию можно определить методом Find:
pos = IntList.Find(2, IntList.GetHeadPosition() );
cout << "Для поиска элемента равного 2 = " << IntList.GetAt(pos) << endl;
Получим в результате (начиная с 0):
Для поиска элемента равного 2 = 2
Метод SetAt позволяет заменить один элемент в списке на другой:
IntList.SetAt(pos, 33);
for( pos = IntList.GetHeadPosition(); pos != NULL ; )
{
cout << "Новый IntList = " << IntList.GetAt(pos) << endl;
IntList.GetNext( pos); };
Получим результат:
Новый IntList = 0
Новый IntList = 1
Новый IntList = 33
С помощью метода InsertAfter и InsertBefore можно добавить в середину после вычисленной ранее позиции и до нее:
Print_Clist( IntList );
IntList.InsertAfter(pos, 55);
IntList.InsertBefore(pos, 44);
Print_Clist( IntList );
Получим результат:
Список [0] = 0
Список [1] = 1
Список [2] = 44
Список [3] = 33
Список [4] = 55
Метод печати Print_Clist опишем в заголовочном файле следующим образом:
void Print_Clist(CList<int, int> & Cl)
{
POSITION pos;
int i = 0;
if ( !Cl.IsEmpty())
for( i = 0, pos = Cl.GetHeadPosition(); pos != NULL ; i++)
{
cout << "Список ["<< i << "] = " << Cl.GetAt(pos) << endl;
Cl.GetNext( pos);
}
else
cout << "Список пуст!"<< endl; };
Метод IsEmpty позволяет проверить пустой список. Метод GetNext вычисляет следующую позицию в списке. Вычисление позиции начала (GetHeadPosition) и конца (GetTailPosition) списка может быть выполнено так:
pos = IntList.GetHeadPosition();
cout << "Для головы списка элемент = " << IntList.GetAt(pos) << endl;
pos = IntList.GetTailPosition();
cout << "Для хвоста списка элемент = " << IntList.GetAt(pos) << endl;
Получим результат:
Для головы списка элемент = 0
Для хвоста списка элемент = 55
С помощью методов (RemoveHead, RemoveTail, GetHead, GetTail, AddHead, AddTail) можно удалять, добавлять элементы списка, получать значения из головы и хвоста списка:
IntList.RemoveHead();
IntList.RemoveTail();
//
cout << "Для головы списка элемент (GetHead) = " << IntList.GetHead() << endl;;
cout << "Для головы списка элемент (GetTail) = " << IntList.GetTail() << endl;;
//
IntList.AddHead( 10 );
IntList.AddTail( 50 );
Print_Clist( IntList );
Получим результат:
Для головы списка элемент (GetHead) = 1
Для головы списка элемент (GetTail) = 33
Список [0] = 10
Список [1] = 1
Список [2] = 44
Список [3] = 33
Список [4] = 50
Для подсчета числа элементов в списке используется метод GetCount:
cout << "Число элементов в списке (GetCount) = " << IntList.GetCount() << endl;
Получим результат:
Число элементов в списке (GetCount) = 5
С помощью метода FindIndex можно найти элемент списка по номеру:
pos = IntList.FindIndex(3 ); // Порядковый номер элемента в списке 3 (считаем от нуля)
cout << "Для поиска индекса 3 элемент = " << IntList.GetAt(pos) << endl;
Получим результат:
Для поиска индекса 3 элемент = 33
С помощью метода RemoveAll можно удалить все элементы списка:
IntList.RemoveAll();
Print_Clist( IntList );
Получим результат:
Список пуст!
Для объектов собственного класса (в примере Point) почти все методы работают аналогично. Описание и заполнение списка из Point:
CList<Point , Point> PList;
for (i = 0 ; i < 3 ; i++ )
PList.AddTail( *new Point(i,i));
cout << "Цикл вывода из списка Point !" << endl;
for( pos = PList.GetHeadPosition(); pos != NULL ; )
{
cout << " PList = " << PList.GetAt(pos) << endl;
PList.GetNext( pos); };
Получим результат:
Цикл вывода из списка Point !
PList = { x = 0 y = 0 }
PList = { x = 1 y = 1 }
PList = { x = 2 y = 2 }
Метод Find (поиск по объекту) требует перегрузки операции сравнения (“= =”), конструктора копирования для класса Point. Например:
Point(const Point & p){ x = p.x ; y = p.y ;}; // Конструктор копирования
Point & operator=(const Point & p){ x = p.x ; y = p.y ; return *this;}; // Перегурузка присваивания
friend bool operator= =(const Point & p1 , const Point & p2) ;
…
// Перегурузка операции сравнения – равенства для удаления по объекту
bool operator= =(const Point & p1 , const Point & p2)
{
return ( (p1.x= =p2.x) && (p1.y= =p2.y) );
};
Тогда для следующего фрагмента программы:
pos = PList.Find( Point(2,2));
cout << "Find Point(2, 2) для PList = " << PList.GetAt(pos) ;
Получим результат:
Find Point(2, 2) для PList = { x = 2 y = 2 }
Для методов FindIndex и RemoveAll следующего фрагмента программы:
Print_PL(PList);
pos = PList.FindIndex( 1);
cout << "FindIndex( 1) для PList = " << PList.GetAt(pos) ;
PList.RemoveAll();
Print_PL(PList);
Получим результат:
PoList = { x = 0 y = 0 }
PoList = { x = 1 y = 1 }
PoList = { x = 2 y = 2 }
FindIndex( 1) для PList = { x = 1 y = 1 }
Список пуст!
Для класса списков CObList также все методы аналогичны. Существенное отличие заключается в том, что такой список поддерживает список указателей на объекты типа CObject, или точнее, объекты классов наследованных от CObject. В этом случае их описание эквивалентно такому:
CObList PoList;
for (i = 0 ; i < 3 ; i++ )
PoList.AddTail( (CObject *)new Point(i,i));
cout << "Цикл вывода из списка CObList Point !" << endl;
for( pos = PoList.GetHeadPosition(); pos != NULL ; )
{ cout << "PList = " << *((Point *)(PoList.GetAt(pos))) << endl;
PoList.GetNext( pos); };
Получим результат: