1. C++ / Говнокод #8426

    +1002

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    template<class fwd, class Predicat>
    fwd findLast(fwd one, fwd last, Predicat P)
    {
              if (one == last) return one;
              fwd s = one;
              fwd tt = ++s;
              for ( ; s!=last; )
              { 
                   s = find_if(s, last, P);
                   if (s != last) { tt=++s;  }
              }
              return tt;
    }

    Функция для поиска последнего вхождения элемента в контейнере STL с помощью алгоритма find_if.

    Запостил: Stanislaw374, 05 Ноября 2011

    Комментарии (79) RSS

    • автор забыл про reverse_iterator
      Ответить
      • А еще смущает совпадение условий в for() и if().
        Ответить
        • Проще сказать, что здесь НЕ смущает... хотя не, не проще. Не нашёл такого. :(
          Ответить
          • ну, вроде точки с запятыми правильно расставлены :)
            Ответить
        • Не смущайтесь, смелее!
          Ответить
      • Судя по всему, это — однонаправленный итератор. Так что код не говно. Только ищет он не последнее вхождение, а итератор сразу за последним вхождением.
        Ответить
        • > элемента в контейнере STL
          Ответить
          • slist в достандартной SGI STL.
            std::forward_list в C++11.
            Ответить
            • подловил
              тем не менее, даже для такого "популярного" forward_list функция написана безобразно
              Ответить
              • А как иначе? Код идеальный, ничего не изменишь без ухудшения.
                Ответить
                • даже если предположить, что автор реально хотел возвращать элемент, следующий за искомым (последним в контейнере, удовлетворяющим предикату), возвращать второй элемент контейнера, если ничего не нашли - бред
                  но я, пожалуй, поверю тому, кто запостил говнокод, и его описанию, что на самом деле должен был делать код - найти последний удовлетворяющий элемент в контейнере
                  кодер, наверное, хотел писать s++, это бы имело как раз больше смысла (кроме начала, конечно, там что ++s, что s++ бред)
                  идеальный код - использовать файд_иф и реверс_итератор везде, где это возможно, и конкретно для форвард_листа (ну или в той говноархитектуре, где хочется именно искать с начала в любом контейнере) пользоваться
                  template <class FwdIter, class Pred>
                  FwdIter find_last_fwd(FwdIter first, FwdIter last, Pred pred)
                  {
                  	FwdIter found = last;
                  	while (first != last) {
                  		if (pred(*first))
                  			found = first;
                  		++first;
                  	}
                  	return found;
                  }
                  Ответить
                  • Этот код не тождественен исходному. Если автор имел в виду именно то, что написал (а иначе трудно объяснить tt = ++s), то ни прибавить, ни отнять (ну разве что от локальной переменной избавиться, итерируя по параметру, но это придирки).
                    Ответить
                    • если нужно следующий после требуемого - код должен быть еще проще
                      while (first != last)
                      	if (pred(*first++))
                      		found = first;

                      вот ведь упёртый дед
                      Ответить
                      • Постфиксный инкремент менее эффективен. И как же киллер-фича — возврат второго элемента, если ничего не найдено?
                        Ответить
                • 1)std::forward_list не нужен. Ошибка проектирования.
                  >Код идеальный, ничего не изменишь без ухудшения.
                  2) Превратить О(n) в О(n^2) - это идеально.
                  http://ideone.com/c5nS3
                  Вывод:
                  Код говно, автор мудак.
                  Ответить
                  • зачем так грубо?
                    Ответить
                  • Да, так не нужен, что его наконец-то легализировали в новом стандарте. Между прочим, самая популярная структура в достандартном C++, C и многих других языках (не говоря уж о Lisp).
                    Ответить
                    • а лисп не язык чтоли?
                      Ответить
                      • У Лиспа с однонаправленными списками особые отношения.
                        Ответить
                    • >Между прочим, самая популярная структура в достандартном C++
                      Это преждевременная оптимизация. То, к чему она привела можно увидеть на примере данного говнокода. Ещё и лишние тормоза получили из-за неумения писать код для односвязанного списка. Сначала нужно было std::list юзать, а когда закончил писать блок проги и слезно понадобилась оптимизация по объему памяти, то можно переходить на std::forward_list.
                      Преждевременная оптимизация root of all evil.
                      Ответить
                  • Оба алгоритма — O(n).
                    Ответить
                    • сложность find_if тоже учитывай
                      Ответить
                      • оба алгоритма O(n)
                        Ответить
                        • показать все, что скрытода, у find_if сложность О(n) и у цикла представленного в данном говнокоде тоже сложность О(n). Так что у обоих О(n). Но в данном ГК они вложены друг в друга и получается О(n^2). Такая простая математика. Никакого матана.
                          Ответить
                          • это фейл, они не вложены друг в друга, они вместе образуют цепочку действий, позволяющих тупо пройти контейнер за n шагов
                            Ответить
                            • ты вообще отличаешь
                              for (...)
                              { 
                                       s = find_if(s, last, P);
                                        ...
                              }
                              от не вложенной цепочки действий
                              for (...)
                              { 
                                        ...
                              };
                               s = find_if(s, last, P);
                              ?
                              Ответить
                              • ты вообще понимаешь, что после вызова find_if текущему итератору контейнера s присваивается то, что найдет find_if
                                ты сегодня фейлишься больше обычного, сосредоточься!
                                Ответить
                              • Он прав, действия не вложены, они образуют цепочку.
                                Это видно хотя бы по тому, что итератор прогоняется вдоль цикла только один раз. Внутренний прогон учитывается во внешнем.
                                Ответить
                              • Он же не от начала ищет, а со смещением. Линейная сложность. я тоже после праздников не в себе
                                Ответить
                          • Это пять!
                            Ответить
                      • Разумеется.
                        Ответить
    • А я вот не врубился, что это делает.
      Ответить
      • возвращает следующий элемент после последнего вхождения требуемого в контейнере, либо если ни одного не нашел, то второй, очевидно же
        Ответить
        • А, понял.
          Да, забавно, искать последний элемент, ищя с начала.
          Ответить
          • показать все, что скрытоАлгоритм маляра Шлемиля.
            Ответить
          • лол, я написал "я" в слоге "ща"
            Ответить
          • В односвязном списке иначе не получится.
            Ответить
            • Зачем заводить односвязный список в задачах, где надо искать последний элемент?
              Ответить
              • Может когда заводили, не собирались искать последний. Или эта операция так редка, что пусть.

                А так — экономия памяти (до двух раз), быстрее модификация (раза в два).
                Ответить
              • показать все, что скрыто>Зачем заводить односвязный список в задачах, где надо искать последний элемент?
                Вполне возможно, что в данной задаче этот самый последний элемент, но равный заданному, с большой вероятностью (это особенность конкретной задачи) лежит ближе к началу списка. Искать с конца в таком случае не имеет смысла. Поэтому можно применять односвязанный список. Если применять тот алгоритм, что работает за О(n) (а не тот, что в ГК за О(n^2)), то при учитывании данной особенности задачи (то условие, что последний равный элемент скорее всего лежит намного ближе к началу, чем к концу). То сложность данной задачи очень часто может вырождаться до сложности О(с) при c намного меньше n. Это будет намного эффективней применения традиционного std::list с реверсированными итераторами для данной конкретной задачи.
                Ответить
                • хуясе теоретик
                  как это ты сможешь остановиться на 10-м элементе в контейнере из 100, считая что этот элемент - действительно последний в контейнере
                  ты же не проверял остальные 90
                  Ответить

    Добавить комментарий