Russian Qt Forum
Ноябрь 24, 2024, 19:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6 ... 12   Вниз
  Печать  
Автор Тема: Тренировка навыков быстрого программирования  (Прочитано 80954 раз)
Hrundel
Гость
« Ответ #45 : Февраль 14, 2014, 13:03 »

Так я не понял, ты решил проигнорировать поставленную задачу? Или ты надеешься, что тебе на работе таких заданий давать не будут? Думаешь что будешь решать упражнения как у твоей подруги на втором семестре?
Это задание как раз на две недели. Я это делал на пятом семестре. За две недели реально выполняется.
« Последнее редактирование: Февраль 14, 2014, 13:04 от Hrundel » Записан
8Observer8
Гость
« Ответ #46 : Февраль 14, 2014, 15:11 »

Напиши программу визуализирующую ненаправленые взвешанные графы до 50 узлов.

Условия к решению обычно прилагаются, поэтому даю условия:

1. Разработать структуру данных с вожмозностью быстрого перехода от узла к узлу по кантам.
2. Реализовать трассировку от любого узла.
3. Реализовать ввод данных из файла (парсинг) любого наиболее удовлетворяющего задаче формата файла.

Можете привести пример, где на практике это будет нужно? Пример из Вашей практики, так сказать.
« Последнее редактирование: Февраль 14, 2014, 15:22 от 8Observer8 » Записан
8Observer8
Гость
« Ответ #47 : Февраль 14, 2014, 15:16 »

Код
C++ (Qt)
int main(int argc, char** argv)
{
 std::vector <int> vec;
 
// получаем имя файла из командной строки, если там пусто, то input.txt (по умолчанию)
 std::string iFileName = GetInName(argc, argv);
 
// читаем данные из файла
 int err = ReadData(iFileName, vec);
 if (err) return ShowError(err, &iFileName);
 
// выполняем содержательную часть
 int result;
 err = sumOfMaxAndMin(arr, &result);
 if (err) return ShowError(err, &iFileName);
 
// записываем выходной файл
 std::string oFileName = GetOutName(argc, argv);
 err = WriteResult(oFileName, result);
 if (err) return ShowError(err, &oFileName);
 
 return 0;
}
Теперь начинаем парить ReadData и др ф-ции, там тоже выделяем ф-ции, их будет уже меньше - и так до тех пор пока не напишем все. Когда Вы все это сделаете (аккуратно, с любовью а не абы как) - Вы с удивлением обнаружите что in.close() не понадобился ни разу  :)

Igors, при реализации Вашей идеи я испытал большую радость! Спасибо Вам огромное! Теперь мне самому стало легче и приятнее читать свой код.

close() вызываю один раз для входного файла и один раз для выходного (внутри функций чтения и записи).

Код
C++ (Qt)
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
 
int readData(const std::string& iFileName, std::vector<int>& arr);
int writeResult(const std::string& oFileName, int &result);
int showError(int err, const std::string& fileName);
int sumOfMaxAndMin(const std::vector<int>& arr, int& result);
 
int main(int argc, char** argv) {
 
   // Массив для хранения входных данных
   std::vector <int> arr;
 
   // Имя входного файла
   std::string iFileName = "input.txt";
 
   // Читаем данные из файла
   int err = readData(iFileName, arr);
   if (err) return showError(err, iFileName);
 
   // Выполняем содержательную часть
   int result;
   err = sumOfMaxAndMin(arr, result);
   if (err) return showError(err, iFileName);
 
   // Записываем выходной файл
   std::string oFileName = "output.txt";
   err = writeResult(oFileName, result);
   if (err) return showError(err, oFileName);
 
   return 0;
}
 
/**
* Читаем данные из файла
*
* @param iFileName Имя входного файла
* @param vec Массив, в который будут считаны входные данные
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле некорректные данные
*/

int readData(const std::string& iFileName, std::vector<int>& arr) {
 
   // Открываем файл с входными данными
   std::ifstream in;
   in.open(iFileName.c_str());
   if (!in.is_open()) {
       return 1;
   }
 
   // Читаем данные из файла
   int value, err = 0;
   std::string input;
   while (in >> input) {
       if (std::stringstream(input) >> value) {
           arr.push_back(value);
       } else {
           err = 2;
           break;
       }
   }
 
   // Закрываем файл и возвращаем код ошибки
   in.close();
   return err;
}
 
/**
* Записываем результат выходной в файл
*
* @param iFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int& result) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << result << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 
/**
* Выводит текст с ошибкой на экран
*
* @param err Код ошибки
* @param iFileName Имя файла, в котором произошла ошибка
*/

int showError(int err, const std::string& fileName) {
   switch (err) {
       case 1:
           std::cerr << "Error: could not open the file " << fileName.c_str() << std::endl;
           break;
       case 2:
           std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
           break;
       default:
           std::cerr << "Error code: " << err << "; file name: " << fileName.c_str() << std::endl;
           break;
   }
 
   return err;
}
 
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @param result Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
* @return Код ошибки
*/

int sumOfMaxAndMin(const std::vector<int>& arr, int& result) {
 
   // Массивы для чисел с чётным и нечётными номерами
   std::vector<int> odd;
   std::vector<int> even;
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   // Сортируем на чётный и нечётные массивы
   for (int i = 0; i < size; ++i) {
       if ((i+1)%2 != 0) {
           odd.push_back(arr[i]);
       } else {
           even.push_back(arr[i]);
       }
   }
 
   // Находим минимальный среди нечётных
   int min = 0;
   if (odd.size() > 0) {
       min = *std::min_element(odd.begin(), odd.end());
   }
 
   // Находим максимальный среди чётных
   int max = 0;
   if (even.size() > 0) {
       max = *std::max_element(even.begin(), even.end());
   }
 
   // Вычисляем результат
   result = max + min;
 
   // Возвращаем код ошибки
   return 0;
}
 

P.S. Это решение вот этой задачи: http://acmp.ru/index.asp?main=task&id_task=272
Время: 0,208 сек
Память: 1064 Кб

« Последнее редактирование: Февраль 14, 2014, 15:27 от 8Observer8 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #48 : Февраль 14, 2014, 15:25 »

Я сдал вот эту задачу: http://acmp.ru/?main=task&id_task=50

Она правильно решена, но я бы хотел услышать вашу критику кода, подхода к решению и т.д.

Я буду переписывать содержимое main.cpp, как посоветовал Igors в ответе #16. Меня сейчас интересует, то как можно улучшить и упростить код (который в функциях, а не в main). А может всё нормально?
Алгоритм (содержательная часть). Пока нет понятия что все чего-то стоит, весит. Использован std::set - зачем? Ведь ассоциативный контейнер - удовольствие дорогое. И зачем здесь вообще нужен контейнер? Рассмотрим циклический сдвиг

- abcd  // было
- dabc  // стало

Кто же мешает найти сначала "d" и затем проверить не заканчивается ли найденное на "аbc"? Этот алгоритм использует 0 (ноль) памяти, и по меньшей мере на порядок быстрее.

А тут вообще распустился
Цитировать
int amountOfSubstrings(string inStr, string substr) {
Какого подавать данные по значению вызывая их копирование? Здесь не Qt где имплисит шара попку подмоет.

Относитесь к задаче более вдумчиво и аккуратно (чему кстати отлично учит язык С). Бездумно ляпать контейнерами - ума много не надо.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #49 : Февраль 14, 2014, 15:29 »

Теперь мне самому стало легче и приятнее читать свой код.
Читать может и стало приятней, только вот использовать такие функции повторно вряд ли получиться.
Одна из целей выделения кода в отдельную функцию - это повторное использование этого кода в других местах программы.
Давайте посмотрим на прототипы ваших функций:
int readData(const std::string& iFileName, std::vector<int>& arr);
int writeResult(const std::string& oFileName, int &result);

и ответим на вопрос, а смогу ли я использовать эти функции для загрузки/сохранения данных из другого источника, например, сети, середины файла или текстового буфера в крайнем случае? Нет.

Теперь давайте вспомним про потоки (stream) и для чего они вообще в C++ были придуманы. Как раз для того, что бы функции могла работать с разными источниками данных одним и тем же способом. И если изменить реализацию функций на следующий, то функции больше не придется переписывать, достаточно будет давать на вход нужный поток.
int readData( istream &is, std::vector<int>& arr );
int writeResult( ostream &os, int result );

Записан
Bepec
Гость
« Ответ #50 : Февраль 14, 2014, 16:06 »

А меня больше интересует что в моём коде неправильно Смеющийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Февраль 14, 2014, 16:10 »

И если изменить реализацию функций на следующий, то функции больше не придется переписывать, достаточно будет давать на вход нужный поток.
int readData( istream &is, std::vector<int>& arr );
int writeResult( ostream &os, int result );

Это имеет свои резоны, но в повторном использовании можно усомниться. Напр выглядит более вероятно что изменится не тип ввода (что-то будет вместо файла), а тип данных (что-то др вместо вектора int). С др стороны есть работа которую можно поручить readData (string) - хоть проверить открытие файла. Ну никто не мешает "декомпозировать" ее на более мелкие ф-ции и readData (stream) будет одной из них.

В любом случае главное - выделять/разделять I/O, UI и расчетную части, а не валить все в кучу которая развалится при первом же изменении.

Да, и константы/песики надо понаводить (enum), а то 1, 2. 3 потом хрен найдешь

Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #52 : Февраль 14, 2014, 16:31 »

С др стороны есть работа которую можно поручить readData (string) - хоть проверить открытие файла.
Проверять открытие файла в функции readData? Вам нравится это название? А поручить ей можно еще много чего, название серьезное. Улыбающийся

Ну никто не мешает "декомпозировать" ее на более мелкие ф-ции и readData (stream) будет одной из них.
Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
Записан
BuRn
Гость
« Ответ #53 : Февраль 14, 2014, 18:51 »

[ОФТОП]
Мне кажется, или человек занимается какой-то хер...ей простите ? Из диалогов выше, я так понял, что чел на форуме решил обучиться программированию на задачках уровня 1-2 курс универа.
Записан
Nidxogg
Гость
« Ответ #54 : Февраль 14, 2014, 18:56 »

Для понимания есть задачки получше?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #55 : Февраль 14, 2014, 20:46 »

Проверять открытие файла в функции readData? Вам нравится это название? А поручить ей можно еще много чего, название серьезное. Улыбающийся
Название вполне нравится, только "R" (большое) лучше, ну это дело вкуса. Я четко вижу/уверен что ввод данных надо выделить, размазывать его в main явно плохо.

Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
То палка о двух концах. Дальше возникнет идея сделать ввод универсальным, перекрыть оператор >>, пойдут в ход злополучные темплейты и.т.д. Стоит ли так увлекаться? Мое мнение - нет, пока достаточно локализовать ввод, а дальше посмотрим.

[ОФТОП]
Мне кажется, или человек занимается какой-то хер...ей простите ? Из диалогов выше, я так понял, что чел на форуме решил обучиться программированию на задачках уровня 1-2 курс универа.
Не то чтобы я приветствую этот метод - но вынужден признать что он "не хуже остальных". Многое зависит от того как подходить к задаче (пусть простой). Препод не будет вдаваться в концепции/идеологию, нет возможности (а часто и желания), ему надо чтобы дите хоть что-то освоило и не оборзело. А на форуме бьют (что вполне норм) - ну пока наш герой стойко это выдерживает  Улыбающийся

А меня больше интересует что в моём коде неправильно Смеющийся
Вы лучше расскажите как это Вы сократили себе объем работы в неск раз избавившись от всякого утомительного контроля ошибок? Правильно ли я понимаю что это "непринципиально", "никак не влияет на суть" и.т.п. ?   Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #56 : Февраль 14, 2014, 20:56 »

Я четко вижу/уверен что ввод данных надо выделить, размазывать его в main явно плохо.
Так не размазывайте. Никто же не заставляет. Улыбающийся

Мое мнение - нет.
Ок.
Записан
Bepec
Гость
« Ответ #57 : Февраль 14, 2014, 21:11 »

Igors какие ошибки? Зачем? У программы есть чёткие условия. Они не размазаны, как ваши задачи. Запуск, чтение из input, вывод в output. Человека нет в этой схеме.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #58 : Февраль 14, 2014, 21:22 »

Igors какие ошибки? Зачем?
Признаюсь - Вы меня поставили/загнали в тупик. Единственный ответ что приходит в голову типа "ну а совесть есть? Ведь так юзверь не сможет работать" - но это звучит как-то напыщенно, старомодно, неудобно и говорить  Плачущий
Записан
8Observer8
Гость
« Ответ #59 : Февраль 14, 2014, 21:26 »

Спасибо, ребят! Много классной инфы. Я завтра всё проработаю.

Вот функция из предыдущего сообщения. Что о ней скажете? Не скупитесь в критике

Код
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @param result Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
* @return Код ошибки
*/
int sumOfMaxAndMin(const std::vector<int>& arr, int& result) {
 
   // Массивы для чисел с чётным и нечётными номерами
   std::vector<int> odd;
   std::vector<int> even;
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   // Сортируем на чётный и нечётные массивы
   for (int i = 0; i < size; ++i) {
       if ((i+1)%2 != 0) {
           odd.push_back(arr[i]);
       } else {
           even.push_back(arr[i]);
       }
   }
 
   // Находим минимальный среди нечётных
   int min = 0;
   if (odd.size() > 0) {
       min = *std::min_element(odd.begin(), odd.end());
   }
 
   // Находим максимальный среди чётных
   int max = 0;
   if (even.size() > 0) {
       max = *std::max_element(even.begin(), even.end());
   }
 
   // Вычисляем результат
   result = max + min;
 
   // Возвращаем код ошибки
   return 0;
}

Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
То палка о двух концах. Дальше возникнет идея сделать ввод универсальным, перекрыть оператор >>, пойдут в ход злополучные темплейты и.т.д. Стоит ли так увлекаться? Мое мнение - нет, пока достаточно локализовать ввод, а дальше посмотрим.

Это очень интересная тема (оператор >>, темплейты). Замечания по алгоритмам к задачам устраню. А тем временем буду думать об улучшении функциий (чтение, запись), чтобы сделать их универсальными. Дайте, пожалуйста, задание, куда двигаться дальше по улучшению.

Цитировать
Да, и константы/песики надо понаводить (enum), а то 1, 2. 3 потом хрен найдешь
Что такое песики?
« Последнее редактирование: Февраль 14, 2014, 21:33 от 8Observer8 » Записан
Страниц: 1 2 3 [4] 5 6 ... 12   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.116 секунд. Запросов: 24.