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

    +997

    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
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    Can you think of an algorithm that performs the below:
    “The Big Brown Fox”    	     => “Fox Brown Big The”
    “How are you?”                 => “you? are How”
    
    std::string reverse_words( const std::string& str )
    {
      std::string result;
      result.reserve( str.length() );
      
      size_t word_begin = 0;
      while( word_begin < str.length() )
      {
        const size_t pos = str.find_first_of( ' ', word_begin );
        pos = (pos != string::npos) ? pos : str.length();
        std::string word = str.substr( word_begin, pos-word_begin );
        word_begin = pos + 1;
    
        if (result.length() > 0)
        {
          word.append( 1, ' ');
        }
        result.insert( 0, word );
      }
      return result;
    }

    высрал буквально 5 минут назад
    inplace версию чего-то влом писать для домашнего теста, да и кода в ней будет больше, но работать она должна быстрее за счет отсутствия аллокаций
    но писать надо, так как отправлять такое как-то стыдно

    Запостил: pushkoff, 17 Декабря 2011

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

    • На Пайтоне в одну строчку.
      Ответить
    • > result.insert( 0, word );
      ну как минимум твой алгоритм можно переделать так, чтобы в результирующую строку вставлять как положено в конец
      еще есть вариант отдать поиск слов в строке std::istringstream
      еще есть вариант использовать временный стек, куда складывать offset и length каждого слова, а потом из этого стека сделать верный результат\
      а еще рекурсивно по строке
      Ответить
      • да, я решил сначала разбить на слова а потом собрать
        Ответить
      • А можно и обратным итератором
        string reverse_words(const string& str)
        {
          string result;
          result.reserve(str.length());
        
          typedef string::const_reverse_iterator CRevIt;
          CRevIt word_end = str.rbegin();
          CRevIt word_begin = str.rbegin();
        
          while(true)
            {
              word_begin = find(++word_begin, str.rend(), ' ');
              result += string(word_begin.base(), word_end.base());
        
              if(word_begin == str.rend())
        	break;
        
              result += string(" ");
              word_end = word_begin + 1; 
            }
          return result;
        }
        Ответить
        • о точно.
          если использовать append то не будет лишних аллокаций
          Ответить
        • собственно эту идею я и имел в виду, когда говорил о правильной вставке
          впрочем, в твоем решении много спорных мест
          вместо += std::string(..) лучше использовать append(it1, it2)
          result += std::string(" ") -> result += ' ';
          если str начнется с пробела, твой результат тоже (ну это надо смотреть требования задачи, конечно)
          и, самое главное, при пустой str не стоит делать ++ к итератору, уже равному rend()

          поможем пушкову с миру по нитке
          рекурсивная версия в копилку предложенных, минусы и плюсы очевидны
          std::string reverse_words(std::string const & str)
          {
          	struct helper {
          		static std::string rev(std::string::const_iterator begin, std::string::const_iterator end,
          			std::string & result)
          		{
          			std::string::const_iterator next_space = std::find(begin, end, ' ');
          
          			if (next_space != end)
          				rev(next_space + 1, end, result);
          
          			if (!result.empty() && begin != next_space)
          				result += ' ';
          
          			return result.append(begin, next_space);
          		}
          	};
          
          	std::string result;
          	result.reserve(str.length());
          	return helper::rev(str.begin(), str.end(), result);
          }


          но такие велосипеды, конечно, не нужно изобретать заново
          Ответить
          • http://ideone.com/ME7SW
            еще хочу привести к более читабельному виду, так как куча индексов меня расстраивает
            Ответить
            • теперь подумай что случится, когда
              str.length() будет равна 0
              Ответить
            • Вот ещё:
              http://ideone.com/DP9a4
              Вот так преобразуется в полный inplace:
              http://ideone.com/etHZP
              Никаких аллокаций.
              Ответить
              • Недочёт у меня есть. Лучше так:
                if(n==e)
                                        break;
                ++n;
                Ответить
                • А это выкинуть:
                  if(n!=e)
                                          ++n;
                  Ответить
                  • Выложу и суда, чтобы не потерялось.
                    Почти inplace:
                    const string reverse_words( string str )
                    {
                    	auto b=str.begin(), e=str.end(), n=find(b, e, ' ');
                    	while(b!=e)
                    	{
                    		reverse(b,n);
                    		if(n==e)
                                            break;
                    		++n;
                    		b=n;
                    		n=find(n, e, ' ');
                    	}
                    	reverse(str.begin(), str.end());
                    	return str;
                    }


                    Полный inplace с абсолютным 0 аллокаций:
                    const string& reverse_words( string& str )
                    {
                    	auto b=str.begin(), e=str.end(), n=find(b, e, ' ');
                    	while(b!=e)
                    	{
                    		reverse(b,n);
                    		if(n==e)
                                            break;
                    		++n;
                    		b=n;
                    		n=find(n, e, ' ');
                    	}
                    	reverse(str.begin(), str.end());
                    	return str;
                    }
                    Ответить
    • к стати затупил, забыл const убрать перед pos
      Ответить
    • > pos = (pos != string::npos) ? pos : str.length();
      А почему не
      if (pos == string::npos)
        pos = str.length();

      Имхо, так очевиднее.
      Не ради холивара, просто хочу узнать мнение.
      Ответить
      • я в таких вычислениях больше оператор ?: люблю, это как-то более ФПшно что ли
        Ответить
        • >ФПшно
          >C++
          Ответить
        • pos = (pos != string::npos) ? pos : str.length();

          масло масляное я понимаю если два новых результата на выбор
          типа res = exp ? first : second
          но тут то одно а второй вообще искуственно смотрится фейк
          одним словом тут логичнее
          if (pos == string::npos)
          	pos = str.length();
          Ответить
    • boost::tokenizer для разбивания на слова.
      std::foreach для каждого слова std::reverse
      std::accumulate для объединения слов обратно.
      Ответить
      • куча аллокаций будет
        Ответить
        • Ну и пофиг. Если будет тормозить, то сооптимизируем после прохода профлаером, зато пишется за 2 строчки.
          Ответить
          • в таком случае лучше было выбрать питон
            сплит по пробелу, реверс результата, и сборка фором, оно наверное даже одной строкой получилось бы
            Ответить
            • А вот зато потом нельзя его соптимизировать, до уровня С++, если сильно понадобится.
              Ответить
              • я считаю что это утилитарная функция и она должна быть изначально максимально оптимальной
                Ответить
                • Я считаю, что если будет время перед релизом проекта, то потом развернешь свои 2 строчки в 15, сделав её оптимальной, если она будет причиной тормозов в проекте.
                  Эта утилитарная функция может вообще только один раз используется за проект, а то через месяц вообще ни разу не будет использоваться после переписывания алгоритмов, тогда зачем нужно было тратить время на неё, раз она перестала использоваться? Пустая трата времени на несколько тысяч утилитарных функций каждый раз.
                  Ответить
                  • Я считаю, что перед релизом проекта времени не будет.
                    Ответить
                    • Если такое произойдет с моими 2мя строчками, то написав в каждой функции проекта лишние 13 строчек, релиз может выйти с серьёзным запаздыванием или проект вообще закроют.
                      Ответить
                      • Релиз и так выйдет с серьезным опозданием. Проект и так закроют. Расслабься и попробуй получать удовольствие от 13 строчек.
                        Ответить
                        • да ты пораженец и писсямист.

                          >Расслабься и попробуй получать удовольствие
                          ещё и любитель в попку?
                          Ответить
                        • >Расслабься и попробуй получать удовольствие от 13 строчек.
                          Мне заняться нечем, кроме как задницу за лишними строчками отсиживать? Я лучше на Канары съезжу.
                          Ответить
            • def rev(words):
                return " ".join(words.split()[::-1])
              Ответить
    • Бля, когда они уже в стандарт С++ добавят boost::StringAlgo?
      Ответить
    • показать все, что скрытогде говно, гейдевица?
      Ответить
    • Пушков решает олимпиадные задачи?
      Ответить
      • да, чтоб навык не потерять.
        Ответить
        • Создай тему на ГД, весь сайт будет меряться, у кого алгоритм быстрее и короче.
          Ответить
          • зачем, я написал говнокод и выложил его. как бы для этого сайт и предназначен
            Ответить
        • > чтоб навык не потерять
          что, работы совсем нет?
          Ответить
          • я люблю собеседования. а работы хватает, предлагают раз в неделю стабильно.
            Ответить
    • показать все, что скрытоvanished
      Ответить

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