Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   STL (http://forum.oszone.net/showthread.php?t=138398)

.::.DIMA.::. 22-04-2009 16:43 1101115

STL
 
Решено

Admiral 22-04-2009 19:37 1101260

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

pva 22-04-2009 22:18 1101438

В зависимости от идеи можно поступить по-разному.
Допустим матрица хранится в виде упорядоченного списка ненулевых элементов: {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 23-04-2009 08:07 1101688

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

template<typename InputIterator, typename OutputIterator>
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<cell_t>(cin), istream_iterator<cell_t>(), static_cast<merge&>(merge1))

merge& copy(istream_iterator<cell_t,char> first, istream_iterator<cell_t,char> 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;
}



Время: 15:21.

Время: 15:21.
© OSzone.net 2001-