Войти

Показать полную графическую версию : STL


.::.DIMA.::.
22-04-2009, 16:43
Решено

Admiral
22-04-2009, 19:37
.::.DIMA.::., дабы многократно не перечитывать файл, его содержимое можно загрузить в память и работать с ней.
В примере про функцию fread() по ссылке в теме Бинарные файлы (http://forum.oszone.net/thread-138194.html) как раз так и поступили.

pva
22-04-2009, 22:18
В зависимости от идеи можно поступить по-разному.
Допустим матрица хранится в виде упорядоченного списка ненулевых элементов: {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
Итератор - это заменитель указателя в с++. Он даёт универсальное представление указателя на элемент контейнера для шаблонов перебора в с++. Пример шаблона копирования:

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;
}




© OSzone.net 2001-2012