C/C++ - STL

Ответить
Аватара пользователя
.::.DIMA.::.

C/C++ - STL

Сообщение .::.DIMA.::. »

Решено
Аватара пользователя
.::.DIMA.::.

Re: C/C++ - STL

Сообщение .::.DIMA.::. »

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

В примере про функцию fread() по ссылке в теме
C/C++ - Бинарные файлы
как раз так и поступили.
Аватара пользователя
Admiral

Re: C/C++ - STL

Сообщение Admiral »

В зависимости от идеи можно поступить по-разному.

Допустим матрица хранится в виде упорядоченного списка ненулевых элементов: {row, col, value}

тогда наша задача пробежать 2 файла и записать 3-й файл с ненулевым результатом в таком же упорядоченном виде. Используем алгоритм merge

Код: Выделить всё

struct cell_t
{
  unsigned row;
  unsigned col;
  double value;
  // для сортировки
  friend bool operator<(const cell_t& a, const cell_t& b) {
    return a.row<b.row || (a.row==b.row && a.col<b.col);
  // для удобства потом
  friend bool operator==(const cell_t& a, const cell_t& b) {
    return a.row==b.row && a.col==b.col;
  // ввод-вывод
  friend ostream& operator<<(ostream& os, const cell_t& a)
  {
      return os << a.row << " " << a.col << " " << a.value;
  }
  friend istream& oeprator>>(istream& is, cell_t& a)
  {
      return is >> a.row >> a.col >> a.value;
  }
};
struct mixer
{
  cell_t prev;
  ostream_iterator<cell_t,char> output_iter;
  mixer() : prev(), output_iter(cout, "\n")
  {
  }  
  // строим хитрый итератор
  mixer& operator*() {return *this;}
  // так чтобы *iter=a давало нужный эфект
  void operator=(const cell_t& a)
  {
     if (prev==a) prev.value += a.value;
     else {
        if (prev.value) *output_iter = prev;
        prev = a;
  }
}
void main()
{
   ifstream matrix1("matrix1.txt");
   ifstream matrix2("matrix2.txt");
   mixer mixer1; // экономим копирования (передаём в шаблон ссылку, а не объект)
   *merge(
       istream_iterator<cell_t>(matrix1), istream_iterator<cell_t>(),
       istream_iterator<cell_t>(matrix2), istream_iterator<cell_t>(),
       static_cast<mixer&>(mixer1)) = cell_t(); // необходимо чтобы выгрузить последний накопленный результат
}
Аватара пользователя
pva

Re: C/C++ - STL

Сообщение pva »

Итератор - это заменитель указателя в с++. Он даёт универсальное представление указателя на элемент контейнера для шаблонов перебора в с++. Пример шаблона копирования:



Код:

Код: Выделить всё

template
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
{
   for(; first!=last; ++first, ++result) *result = *first;
   return result;
}

Есть соглашения по поводу назначения итераторов:

OutputIterator - предназначен для вывода в поток, во всех алгоритмах используются только конструции *iterator=..., и ++iterator или iterator++; (кстати, если компилятор будет ругаться при сборке на operator++() или operator++(int), надо его добавить, пустой)

InputIterator - для ввода с потока ...=*iterator и ++iterator или iterator++. При этом понимается, что значение надо брать и присваивать один раз.

для OutputIterator и InputIterator как правило явный конструктор без параметра строит итератор конца потока.



ForwardIterator - позволяет чтение, запись, оператор ++ (например для стека)

BidirectionalIterator - позволяет чтение, запись, операторы ++,-- (например для списка)

RandomAccessIterator - позволяет всё, что можно делать с указателем



Попробуем раскрыть шаблон copy с классом merge&:



Код:

Код: Выделить всё

// merge merge1
// copy(istream_iterator(cin), istream_iterator(), static_cast(merge1))
merge& copy(istream_iterator first, istream_iterator last, merge& result)
{
   // *first прочитает оператором >> и вернёт значение cell_t из потока
   // *result вернёт result
   // result =... вызовет merge::operator=(const cell_t&), который запишет в поток вывода результат
   // merge::operator++() лучше оставить пустым {} тогда ++result просто пропустится
   for(; first!=last; ++first, ++result) *result = *first;
   // если идти дальше, у istream_iterator пустой operator++, а operator==(const istream_iterator& iter2)
  // возвращает что-то вроде _stream.good()==iter2._stream.good();
  // помним, что last._stream.good() даёт false
  // получили примерно следующее: for(; first._stream.good()!=last._stream.good(); ) result.merge::operator=((first._stream>>first._value ? first._value : cell_t()));
   return result;
}
Ответить

Вернуться в «Программирование и базы данных»