Контейнеры STL. Пример с отображениями, строками и изменением критерия сортировки на стадии выполнения

   
На этом шаге мы рассмотрим более сложный пример.

   
Следующий пример предназначен для опытных программистов, хорошо разбирающихся в STL. Он дает представление как о мощи STL,
так и о некоторых недостатках, присущих этой библиотеке. В частности, демонстрируются приемы:

  • использования отображений;
  • создания и использования объектов функций;
  • определения критерия сортировки во время выполнения программы;
  • сравнения строк без учета регистра символов.
//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include <iterator>
#include <iomanip>
#include <map>
#include <string>
#include <algorithm>
#include <conio.h> //необходимо для getch()

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

// Объект функции для сравнения строк
// - позволяет задать критерий сравнения во время выполнения
// - позволяет сравнивать символы без учета регистра
class RuntimeStringCmp { 
  public:
    // Константы режима сравнения
    enum cmp_mode {normal, nocase}; 
  private:
    // Используемый режим сравнения
    const cmp_mode mode;

    // Вспомогательная функция для сравнения символов без учета регистра 
    static bool nocase_compare (char c1, char c2)
    {
      return toupper(c1) < toupper(c2);
    }
  public:
    // Конструктор: инициализация критерия сравнения 
    RuntimeStringCmp (cmp_mode m=normal) : mode(m) {}
    
    // Сравнение
    bool operator() (const string& s1, const string& s2) const { 
      if (mode == normal) { 
        return s1 < s2;
      } else {
        return lexicographical_compare (s1.begin(), s1.end(),
                                        s2.begin(), s2.end(),
                                        nocase_compare);
     }
    }
};
  
// Тип контейнера:
//  - отображение
//  - ключ: string
//  - значение: string
//  - специальный тип критерия сравнения

typedef map<string,string,RuntimeStringCmp> StringStringMap;

// Функция для заполнения контейнера и вывода его содержимого 
void fillAndPrint(StringStringMap& coll);
 

int main(int argc, char* argv[])
{
  // Создание контейнера с критерием сравнения по умолчанию
  cout << ToRus("Контейнер 1 (Исходные данные):\n");
  StringStringMap coll1;
  fillAndPrint(coll1);

  // Создание объекта для сравнений без учета регистра символов
  RuntimeStringCmp ignorecase(RuntimeStringCmp::nocase);

  // Создание контейнера с критерием сравнения без учета регистра
  cout << ToRus("Контейнер 2 (Упорядоченные данные):\n");
  StringStringMap coll2(ignorecase);
  fillAndPrint(coll2);

  getch();
  return 0;
}

void fillAndPrint(StringStringMap& coll)
{
  // Вставка элементов в произвольном порядке
  coll["Deutschland"] = "Германия"; 
  coll["deutsch"] = "немецкий"; 
  coll["Haken"] = "крючок"; 
  coll["arbeiten"] = "работать"; 
  coll["Hund"] = "собака"; 
  coll["gehen"] = "идти"; 
  coll["Unternehmen"] = "компания"; 
  coll["unternehmen"] = "принять"; 
  coll["gehen"] = "ходить"; 
  coll["Bestatter"] = "услуги";

  // Вывод элементов 
  StringStringMap::iterator pos; 
  cout.setf(ios::left,ios::adjustfield); 
  for (pos=coll.begin(); pos!=coll.end(); ++pos) { 
    cout << setw(15) << pos->first.c_str() << " " 
         << ToRus(pos->second) << endl;
  }
  cout << endl;
}

//---------------------------------------------------------------------------

Текст этого примера можно взять здесь.

   
Функция main() создает два контейнера и вызывает для них функцию fillAndPrint(), которая заполняет контейнеры одинаковыми
элементами и выводит их содержимое. Однако контейнеры используют разные критерии сортировки.

  • Контейнер coll1 использует объект функции типа RuntimeStringCmp, по умолчанию сравнивающий элементы оператором <.
  • Контейнер соll2 использует объект функции типа RuntimeStringCmp, который инициализируется значением nocase,
    определенным в классе RuntimeStringCmp. При включении режима nocase объект функции сортирует строки без учета регистра
    символов.

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


Рис.1. Результат выполения приложения

   
В первой части итоговых данных выводится содержимое первого контейнера, сравнивающего элементы оператором <. Сначала перечисляются все
ключи, начинающиеся с символов верхнего регистра, а за ними следуют ключи, начинающиеся с символов нижнего регистра.

   
Во второй части ключи сравниваются без учета регистра, поэтому порядок перечисления элементов изменяется. Обратите внимание - вторая часть
содержит на одну строку меньше первой. Дело в том, что при сравнении без учета регистра слова "Unternehmen" и "unternehmen"
оказываются равными, а критерий сортировки нашего отображения не допускает наличия дубликатов. К сожалению, в результате
возникает путаница - ключу, которому должно соответствовать значение "компания", соответствует значение "принять".
Вероятно, в этом примере было бы правильнее использовать мультиотображение. Обычно в качестве словарей применяется именно этот тип контейнера.

   
Со следующего шага мы начнем рассматривать другие контейнеры STL.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий