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

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Помогите решить задачку, верней билет. желательно с пояснениями (http://forum.oszone.net/showthread.php?t=162341)

DimanXP91 04-01-2010 18:46 1310722

Помогите решить задачку, верней билет. желательно с пояснениями
 
Вариант 7
Описать класс с именем MARSH, содержащий следующие элементы:
• Поля: название начального пункта маршрута, название конечного пункта маршрута, номер
маршрута.
• Методы: конструктор по умолчанию, конструктор с тремя параметрами для заполнения всех
полей класса, конструктор копирования, деструктор, операция присваивания, операция
сравнения «меньше» (операция возвращает истину, если номер маршрута у первого операнда
меньше чем у второго, ложь - в противном случае), функция вывода на экран значений полей
класса.
Память для строк - полей класса выделять динамически.
с помощью текстового редактора создать файл и записать в него данные для массива из восьми
элементов типа MARSH.
Написать программу, выполняющую следующие действия:
• ввод из файла данных в динамический массив, состоящий из восьми элементов типа MARSH;
• упорядочить массив по возрастанию номеров маршрутов;
• вывод на экран информации о маршруте, номер которого введен с клавиатуры;
• если таких маршрутов нет, выдать на дисплей соответствующее сообщение.

pva 07-01-2010 03:15 1312998

С использованием стандартной библиотеки C++ будет выглядеть примерно так:
Код:

#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <list>
using namespace std;

class March
{
public:
        // деструктор ~March(), который создаётся автоматически
        // вполне нас устраивает

        // автоматический конструктор копирования (почленное копирование) тоже годится.
        // автоматический оператор присваивания также должен работать почленно.

        March() : _number(unsigned()) {}
        // нужно для использования контейнеров

        March(string const& begin, string const& end, unsigned number) :
                _begin(begin), _end(end), _number(number)
        {
        }

        // оператор << лучше сделать внешним из логических соображений:
        // он равнозначно относится и в `a` и к `b`
        friend bool operator<(March const& a, March const& b)
        {
                return a._number < b._number;
        }

        friend ostream& operator<<(ostream& os, March const& a)
        {
                return os << __tag_begin << "\t" << a._begin << "\n"
                        << __tag_end        << "\t" << a._end << "\n"
                        << __tag_number        << "\t" << a._number << "\n";
        }

        friend istream& operator>>(istream& is, March& a)
        {
                string tag;

                // в случае неудачного чтения из потока (а именно несовпадения названий тэгов)
                // помечаем поток неверным (и прерываем дальнейшее его использование)
                // все остальные проверки нужны чтобы вовремя остановиться.
                if (!(is >> tag) || (tag!=__tag_begin) || !getline(is, a._begin) ||
                        !(is >> tag) || (tag!=__tag_end) || !getline(is, a._end) ||
                        !(is >> tag) || (tag!=__tag_number) || !getline(is, a._number))
                {
                        is.setstate(ios::failbit);
                }

                // здесь скрыта потенциальная угроза порчи данных в исключительной ситуации:
                // когда класс March будет недопрочитан (например неправильный формат файла)
                // непрочитанные поля сохранят значения, с которыми они зашли в оператор чтения
                // из потока. Чтобы этого не случилось, желательно копировать элементы в контейнер,
                // а не читать прямо внутри его. Пример будет ниже.
               
                return is;
        }

        // публикуем для поиска
        unsigned number() const {return _number;}

private:
        string _begin, _end;
        unsigned _number;

        // так мы позволим менять форму ввода-вывода
        static string const __tag_begin, __tag_end, __tag_number;
};

string const March::__tag_begin("begin:"), March::__tag_end("end:"), March::__tag_number("number:");

void main()
{
        // в данном случае 2-связный список предпочтительней вектора
        // потому что класс March тяжело копируется (содержит 2 динамические строки)
        // для сортировки желательно использовать список либо вектор указателей.
        // Создаём список из 8 одинаковых элементов.
        list<March> marchs(8, March(string(), string(), 0U));

        {
                ifstream fin("data.txt");

                // загружаем данные от начала до конца списка
                for(list<March>::iterator out_first=marchs.begin(), out_last=marchs.end();
                        out_first!=out_last && (fin>>*out_first); ++out_first)
                {
                        // пример уязвимости при чтении: если при чтении 4-го элемента произойдёт сбой,
                        // он останется недопрочитанным (сохранит значения, в данном случае присвоенные
                        // по умолчанию).
                }
        }

        marchs.sort();

        // класс-функтор для поиска по номеру маршрута
        struct have_number_t
        {
                unsigned arg;
                have_number_t(unsigned arg1) : arg(arg1) {}
                bool operator()(March& a) {return a.number()==arg;}
        }

        cout << "Номер маршрута? " << flush;
        have_number_t search_number;
        cin >> search_number.arg;
       
        // поиск c использованием search_number.operator()();
        list<March>::iterator found=find_if(marchs.begin(), marchs.end(), search_number);

        if (found!=marchs.end())
        {
                cout << *found << "\n";
        }
        else
        {
                cout << "Не найдено\n";
        }
}

Но если использовать map<unsigned,March>, то March::operator<() не нужен, и всё намного проще:
Код:

#include <map>
//using namespace std;

void main()
{
        map<unsigned,March> march_by_number;

        // класс map сразу использует сортированный список (точнее дерево)
        {
                ifstream fin("data.txt");
               
                // собираем вместе аргумент для map<unsigned,March>::insert()
                // на самом деле map<unsigned,March> хранит элементы не March,
                // а pair<unsigned,March>. Соответсвенно итератор контейнера map
                // будет указывать на элементы этого типа pair<...>. Первый в паре
                // будет ключом для поиска, второй - соотвествующим March.

                pair<unsigned,March> blank_march;

                for(unsigned n=0; n<8 && fin>>blank_march.second; ++n)
                {
                        // готовим ключ для поиска
                        blank_march.first = blank_march.second.number();

                        // добавляем в сортированный список через копирование.
                        // если произойдёт сбой, недочитанный blank_march
                        // не будет помещён в контейнер. Таким образом,
                        // march_by_number содержит только целостные данные.

                        march_by_number.insert(blank_march);
                }
        }

        cout << "Номер маршрута? " << flush;
        unsigned search_number;
        cin >> search_number.arg;
       
        map<March>::iterator found=march_by_number.find(search_number);
        // можно было бы использовать map<...>::operator[](), но он добавляет
        // новые элементы, если таких не было раньше. Нам этого не нужно.

        if (found!=marchs.end())
        {
                // помним что итератор указывает на пару
                cout << found->second << "\n";
        }
        else
        {
                cout << "Не найдено\n";
        }
}



Время: 04:55.

Время: 04:55.
© OSzone.net 2001-