Оцените решение задачи
От: Ororo1  
Дата: 15.10.14 12:29
Оценка:
Условие:
Даны 3 списка с числами. Числа в списках не повторяются. Сами списки отсортированы. Необходимо реализовать метод GetNext, который бы обходил все 3 списка и выдавал числа в порядке возрастания. Объединять списки нельзя!
Примеры списков:
[List]: 1, 5, 12, 28, 31
[List]: 6, 9, 13
[List]: 3, 7, 10, 15
Вывод в этом случае должен быть таким:
GetNext << 1;
GetNext << 3;
GetNext << 5;
GetNext << 6;
GetNext << 7;
GetNext << 9;
и т.д.

Решение:
....

vector<vector<int>*> vectors;//тут хранятся наши списки

vector<int> vec1;
vector<int> vec2;
vector<int> vec3;//сами списки

....

vectors.push_back(&vec1);
vectors.push_back(&vec2);
vectors.push_back(&vec3);

vector<int> indexes(vectors.size(),0);//тут храним индекс элемента, который последний раз брали для каждого из списков

GetNext(indexes);
....


bool isExist(vector<int> &vec, int index)
{
    return index < vec.size();
}

int GetNext( vector<int> &indexes)
{
    int min = 0;
    int index = -1;
    for(int i=0;i<vectors.size();++i)
    {
        if(isExist(*vectors.at(i),indexes.at(i)))
        {
            min = vectors.at(i)->at(indexes.at(i));
            index = i;
            break;
        }
    }
    
    if(index == -1)
        throw exception();
    
    for(int i=0;i<vectors.size();++i)
    {
        if(isExist(*vectors.at(i),indexes.at(i)))
        {
            if(vectors.at(i)->at(indexes.at(i))<min)
            {
                min = vectors.at(i)->at(indexes.at(i));
                index = i;
            }
        }
    }
    
    indexes.at(index)++;
    
    return vectors.at(index)->at(indexes.at(index)-1);
    
}
c++ задачи
Re: Оцените решение задачи
От: Кодт Россия  
Дата: 15.10.14 12:47
Оценка: +1
Здравствуйте, Ororo1, Вы писали:

O>Решение:


Оценка — на 4-
Улучшать можно по-всякому:
— разнести типы значений и индексов
— сделать не на векторах, а по-честному, на списках
— на изменяемых списках это даже проще делается
— at() не нужен, у нас в штатном режиме исключений выхода за границы не возникает — достаточно operator[]
— диагностику конца последовательности можно и без исключений сделать, а, например, отдельной функцией
— для трёх списков можно захардкодить, хотя обобщение на произвольное количество списков — в общем-то, правильный подход
Перекуём баги на фичи!
Re: Оцените решение задачи
От: dead0k  
Дата: 15.10.14 12:59
Оценка: +1
Здравствуйте, Ororo1, Вы писали:

Вместо вектора векторов и вектора индексов логичней использовать 1 вектор итераторов
Хотя я бы сделал проксю на 3 ячейки, которая хранит в себе копии текущих елементов (вместе с итераторами/индексами ессно): выдал наименьший из списка, взял из списка следующий, чтобы лишний раз в память не лазить (хотя это преждевременная оптимизация)

ps/
Впрочем, вру, конечно же, все равно надо еще хвосты запоминать, так-что векторов и с итераторами надо 2 :p
Отредактировано 15.10.2014 13:08 dead0k . Предыдущая версия .
Re[2]: Оцените решение задачи
От: Ororo1  
Дата: 15.10.14 13:07
Оценка:
Здравствуйте, Кодт, Вы писали:

К>- сделать не на векторах, а по-честному, на списках

К>- на изменяемых списках это даже проще делается

Я забыл указать, что по условию можно любой контейнер использовать. Спасибо за коммент, учту на будущее.
Re: Оцените решение задачи
От: Evgeny.Panasyuk Россия  
Дата: 15.10.14 13:10
Оценка: 1 (1)
Вот тут
Автор: Lazin
Дата: 10.07.14
было обсуждение подобной задачи.
В частности, простое решение выглядит вот так:
while(!q.empty())
{
    auto range = heap.top();  
    q.pop();

    //assert(!empty(range));
    *out++ = *begin(range);
    range = make_iterator_range(next(begin(range)), end(range));
    if(!empty(range))
        q.push(range);
}

Легко приводится к интерфейсу GetNext.
Re[2]: Оцените решение задачи
От: Evgeny.Panasyuk Россия  
Дата: 15.10.14 13:15
Оценка:
Здравствуйте, Кодт, Вы писали:

К>- сделать не на векторах, а по-честному, на списках

К>- на изменяемых списках это даже проще делается

А зачем? Тормозить ведь будет. Это же не merge списков в один большой, а просто вывод по отдельности каждого элемента.
Вот если бы в результате нужен был список — то другое дело, действительно проще и быстрее собрать из трёх связанных списков один большой.
Отредактировано 15.10.2014 13:19 Evgeny.Panasyuk . Предыдущая версия .
Re: Оцените решение задачи
От: PM  
Дата: 15.10.14 13:46
Оценка:
Здравствуйте, Ororo1, Вы писали:

Фактически все равно это слияние отсортированных списков, только результат возвращается из GetNext. А как кстати GetNext должен сигнализировать о завершении всех списков? Я видел в коде throw exception.

Комментарии в коде решения

O>Решение:

O>
O>vector<vector<int>*> vectors;//тут хранятся наши списки

// можно хранить списки по значению в векторе, но я бы ограничился массивом
// vector<int> vectors[3];
unsigned const NUM_LISTS = 3;
typedef vector<int> numbers;
numbers lists[NUM_LISTS];

O>vector<int> indexes(vectors.size(),0);//тут храним индекс элемента, который последний раз брали для каждого из списков

// можно вместо индексов хранить const_iterator 
// для используемого в качестве списка vector<int> это не принципиально,
// но для другого типа контейнеров (например list<int>) будет критично
numbers::const_iterator heads[NUM_LISTS];
heads[0] = lists[0].begin();
heads[1] = lists[1].begin();
heads[2] = lists[2].begin();

// GetNext станет такой: ищем минимальный из heads, возвращаем его, продвигаем итератор вперед 
int GetNext()
{
    int min_head = 0;
    for (int i = 0; i < NUM_LISTS; ++i)
    {
        if (heads[i] == lists[i].end()) continue; // пропускаем пройденный список
        if (*heads[i] < *heads[min_head]) min_head = i;
    }
        
    if (heads[min_head] == lists[min_head].end())
        throw exception(); // end of lists

    int min = *heads[min_head];
    ++heads[min_head];
    return min; 
}
O>}
O>
Re: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 14:02
Оценка:
Здравствуйте, Ororo1, Вы писали:

O>

// почему не const& ? У среднестатистического программиста,
// который увидел передачу не-const ссылки, сразу возникает мысль,
// что передаваемый объект будет меняться внутри функции.
O>bool isExist(vector<int> &vec, int index)

O>
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Отредактировано 15.10.2014 14:04 slava_phirsov . Предыдущая версия . Еще …
Отредактировано 15.10.2014 14:03 slava_phirsov . Предыдущая версия .
Re[2]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 14:15
Оценка:
PM>int GetNext()
PM>{
PM>    int min_head = 0;
PM>    for (int i = 0; i < NUM_LISTS; ++i)
PM>    {
PM>        if (heads[i] == lists[i].end()) continue;
PM>        if (*heads[i] < *heads[min_head]) min_head = i; // свалится, когда heads[0] == lists[0].end()
PM>    }
        
PM>    if (heads[min_head] == lists[min_head].end())
PM>        throw exception(); // end of lists

PM>    int min = *heads[min_head];
PM>    ++heads[min_head];
PM>    return min; 
PM>}
O>>}
O>>
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[2]: Оцените решение задачи
От: Ororo1  
Дата: 15.10.14 14:31
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>Здравствуйте, Ororo1, Вы писали:


O>>

_>// почему не const& ? У среднестатистического программиста,
_>// который увидел передачу не-const ссылки, сразу возникает мысль,
_>// что передаваемый объект будет меняться внутри функции.
O>>bool isExist(vector<int> &vec, int index)

O>>


Да, в реальном проекте конечно же желательно const дописать, а в данном случае не принципиально. Индексы вон тоже бы unsigned не помешало сделать.
Re[2]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 14:34
Оценка:
Здравствуйте, PM, Вы писали:


 
    int min = *heads[min_head];
    ++heads[min_head];
    return min;

    return *(heads[min_head]++);
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[3]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 14:37
Оценка:
Здравствуйте, Ororo1, Вы писали:


O>не принципиально


Вообще-то такое должно на автомате писаться. Ну я так думаю


O>Индексы вон тоже бы unsigned не помешало сделать


Основоположники, ЕМНИП, учили использовать unsigned там и только там, где требуются операции с битами.


P.S.

Наташенька, ну вы же сами просили сказать, что я думаю

Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Отредактировано 15.10.2014 14:38 slava_phirsov . Предыдущая версия .
Re[3]: Оцените решение задачи
От: PM  
Дата: 15.10.14 15:05
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

PM>>        if (heads[i] == lists[i].end()) continue;
PM>>        if (*heads[i] < *heads[min_head]) min_head = i; // свалится, когда heads[0] == lists[0].end()

С чего бы, если строкой выше есть проверка с комментарием "пропускаем пройденный список"

Я код проверял на тестовых данных топикстартера, всё отработало.
Re[3]: Оцените решение задачи
От: PM  
Дата: 15.10.14 15:13
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>
_> 
_>    int min = *heads[min_head];
_>    ++heads[min_head];
_>    return min;
_>
_>    return *(heads[min_head]++);
_>


Не хочу ломать голову в приоритете операций, но похоже у тебя сначала идет инкремент итератора и затем его разыменование. И вот тут оно может свалиться. Нужного эффекта можно добиться с
return *heads[min_head]++;
, но постинкременту я предпочитаю явный порядок следования. Кто-то будет это читать и тоже ломать голову. Олдскульных сишников очень мало и они тоже могут ошибаться.

[offtoppic]
Вот не припомню, когда реально без постинкремента было невозможно обойтись. Вот фича, которую надо бы сделать deprecated в С++17 вместо триграфов
[/offtopic]
Re[4]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 15:24
Оценка:
Здравствуйте, PM, Вы писали:

_>>
_>>    return *(heads[min_head]++);
_>>


PM>Не хочу ломать голову в приоритете операций, но похоже у тебя сначала идет инкремент итератора и затем его разыменование. И вот тут оно может свалиться.


С чего бы это? Постфиксный инкремент возвращает предыдущее значение итератора, так что, все честно.

PM>Вот не припомню, когда реально без постинкремента было невозможно обойтись. Вот фича, которую надо бы сделать deprecated в С++17 вместо триграфов


И не надейся! Вангую: deprecated будут объявлены optional и лямбды
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[4]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 15:28
Оценка:
Здравствуйте, PM, Вы писали:

PM>С чего бы, если строкой выше есть проверка с комментарием "пропускаем пройденный список"

PM>Я код проверял на тестовых данных топикстартера, всё отработало.

Ну, это еще ничего не доказывает

Смотри:

 
PM>int GetNext()
PM>{
PM>    int min_head = 0; // Пусть, первый список уже пуст. Тогда heads[min_head] == lists[min_head].end()
PM>    for (int i = 0; i < NUM_LISTS; ++i)
PM>    {
PM>        if (heads[i] == lists[i].end()) continue; // сработает при i == 0
           // здесь мы оказываемся при i == 1, и разыменовываем heads[min_head], т.е. heads[0], т.е. lists[0].end()
           // всё пропало!
PM>        if (*heads[i] < *heads[min_head]) min_head = i;
PM>    }
        
PM>    if (heads[min_head] == lists[min_head].end())
PM>        throw exception(); // end of lists

PM>    int min = *heads[min_head];
PM>    ++heads[min_head];
PM>    return min; 
PM>}
O>>}
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[4]: Оцените решение задачи
От: PM  
Дата: 15.10.14 15:30
Оценка: -1
Здравствуйте, slava_phirsov, Вы писали:

O>>не принципиально


_> Вообще-то такое должно на автомате писаться. Ну я так думаю

+1

O>>Индексы вон тоже бы unsigned не помешало сделать


_> Основоположники, ЕМНИП, учили использовать unsigned там и только там, где требуются операции с битами.

-1

емнип это авторы Java оправдывались почему у них нет беззнаковых целых. Последние удобно использовать в качестве индексов, т.к. для проверки индекса в массиве требуется одно сравнение вместо двух:
bool is_valid_index(int i, int size)
{
    return i >= 0 && i < size;
}

bool is_valid_index(unsigned i, unsigned size)
{
   return i < size;
}


А учитывая, что в стандартной библиотеке для индексов и количества элементов в контейнере используется беззнаковый size_t (с которым кстати в теории можно адресовать в 2 раза больше элементов чем с int), то с is_valid_index(int, int) получим на ровном месте предупреждение компилятора о преобразовании unsigned в int. Которое придется душить явным преобразованием к int

Задолбали такие функции:
void process_string(char const* str, int len);

// приходится их использовать так:
std::string str = "fgfg";
process_string(str.data(), static_cast<int>(str.size()));



И это блин в 21-м веке в С++ коде: https://github.com/v8/v8/blob/master/include/v8.h#L1986
Re[5]: Оцените решение задачи
От: slava_phirsov Россия  
Дата: 15.10.14 15:35
Оценка:
Здравствуйте, PM, Вы писали:

PM>емнип это авторы Java оправдывались почему у них нет беззнаковых целых


А мне наоборот припоминается, что это Страуструп в своем талмуде писал такое. Вот нет под рукой, дойду до него — дам точную ссылку


PM>А учитывая, что в стандартной библиотеке для индексов и количества элементов в контейнере используется беззнаковый size_t (с которым кстати в теории можно адресовать в 2 раза больше элементов чем с int)


Ну вот, да, а в Qt наоборот сплошь и рядом int. Люди не смогли договориться о порядке следования байт, где уж тут знаковость индексов уединообразить. Только диктатура спасет человечество, ИМХО
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[5]: Оцените решение задачи
От: PM  
Дата: 15.10.14 15:51
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>Ну, это еще ничего не доказывает

Это да, надо тестировать на крайних случаях

Возможный фикс:
 
int GetNext()
{
    int min_head = -1;
    for (int i = 0; i < NUM_LISTS; ++i)
    {
        if (heads[i] == lists[i].end()) continue;
        if (min_head == -1 || *heads[i] < *heads[min_head]) min_head = i;
    }

    if (min_head == -1)
        throw exception();

    int min = *heads[min_head];
    ++heads[min_head];
    return min;
}
Re[6]: Оцените решение задачи
От: Evgeny.Panasyuk Россия  
Дата: 15.10.14 15:59
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

PM>>емнип это авторы Java оправдывались почему у них нет беззнаковых целых

_>А мне наоборот припоминается, что это Страуструп в своем талмуде писал такое. Вот нет под рукой, дойду до него — дам точную ссылку

Страуструп да, писал и говорил нечто подобное.
Но если уж и апеллировать к авторитетам, то в области алгоритмов C++ нужно равняться на Степанова — он спокойно использует беззнаковые, и ЕМНИП даже рекомендовал в одной из лекций
Автор: andyp
Дата: 17.07.13
.
Использование знаковых целых, там где по смыслу подходят беззаконные (да ещё и имеют большую "ёмкость") — это что-то из области babysitting'а, причём не особо удачного. Если уж нужна нянька — то тогда уже брать safe int и им подобные.
Отредактировано 15.10.2014 16:01 Evgeny.Panasyuk . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.