2010-09-23 4 views
7

Я пытаюсь изменить порядок слов в предложении, сохраняя пробелы, как показано ниже.Смещение строки в C++

[this is my test string] ==> [string test my is this] 

я сделал в шаг за шагом образом, как,

[this is my test string] - input string 
[gnirts tset ym si siht] - reverse the whole string - in-place 
[string test my is this] - reverse the words of the string - in-place 
[string test my is this] - string-2 with spaces rearranged 

Есть ли другой способ сделать это? Можно ли также сделать последний шаг на месте?

+3

Я хотел бы знать, бизнес-логику этого ... – jcolebrand

+0

@drachenstern Ну, вы можете нужны аналогичные алгоритмы при рендеринге текста bidi. – ybungalobill

+0

Что вы подразумеваете под своим «Возможно ли также сделать последний шаг на месте»? То, что у вас есть, уже делает все на месте. О каком «последнем шаге» вы говорите? – AnT

ответ

5

Ваш подход прекрасен. Но в качестве альтернативы вы можете также сделать:

  • Продолжайте сканирование ввода слов и пространства
  • Если вы нашли слово надвинуть стек S
  • Если вы нашли место (s) епдиеие в номер пространств в очередь Q

После того, как это сделано будет N слова в стеке и N-1 числа в д ueue.

While stack not empty do 
print S.pop 
if stack is empty break 
print Q.deque number of spaces 
end-while 
1

Для слов из первых центральных слов переключения слова н с длиной слова - п Сначала используйте раздвоение функцию, а затем сделать переключение

-1

Я думаю, что я бы просто разметить (strtok или CString :: Tokanize) string с использованием символа пробела. Перетащите строки в вектор, а затем вытащите их в обратном порядке и соедините их промежутком между ними.

+0

с небольшой очисткой вашей логики при поиске промежуточных пространств (нужно сохранить первоначальный порядок пространства). Я бы это сделал только – jcolebrand

+0

. Как бы это поддерживать несколько пробелов между словами, как в его примере между «тестом» и «строкой»? – KeithS

+0

-1: strtok is zomg bad и CString не является стандартным C++ –

1

Этот псевдокод предполагает, что вы не заканчиваете исходную строку пробелом, хотя для этого также могут быть соответствующим образом изменены.

1. Get string length; allocate equivalent space for final string; set getText=1 

2. While pointer doesn't reach position 0 of string, 

    i.start from end of string, read character by character... 
     a.if getText=1 
     ...until blank space encountered 
     b.if getText=0 
     ...until not blank space encountered 

    ii.back up pointer to previously pointed character 

    iii.output to final string in reverse 

    iv.toggle getText 

3. Stop 
0

Все решения strtok работают не для вашего примера, см. Выше. Попробуйте следующее:

char *wordrev(char *s) 
{ 
    char *y=calloc(1,strlen(s)+1); 
    char *p=s+strlen(s); 
    while(p--!=s) 
    if(*p==32) 
     strcat(y,p+1),strcat(y," "),*p=0; 
    strcpy(s,y); 
    free(y); 
    return s; 
} 
+0

Не кажется ли вам немного сумасшедшим, что нужно сделать calloc и сделать что-то настолько концептуально простым? И вы изменяете строку ввода? –

+0

Да, я его модифицирую. Вы не знаете разницу между и ? – user411313

+0

-1: он не работает; +0.5 компилируется (http://codepad.org/8pQGNta3) - итого округлено: 0 – pmg

2

Это подход.

Короче говоря, создайте два списка токенов, которые вы найдете: один для слов, а другой для пробелов. Затем соедините новую строку со словами в обратном порядке и пробелами в прямом порядке.

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

string test_string = "this is my test string"; 

int main() 
{ 
    // Create 2 vectors of strings. One for words, another for spaces. 
    typedef vector<string> strings; 
    strings words, spaces; 
    // Walk through the input string, and find individual tokens. 
    // A token is either a word or a contigious string of spaces. 
    for(string::size_type pos = 0; pos != string::npos;) 
    { 
     // is this a word token or a space token? 
     bool is_char = test_string[pos] != ' '; 
     string::size_type pos_end_token = string::npos; 

     // find the one-past-the-end index for the end of this token 
     if(is_char) 
      pos_end_token = test_string.find(' ', pos); 
     else 
      pos_end_token = test_string.find_first_not_of(' ', pos); 

     // pull out this token 
     string token = test_string.substr(pos, pos_end_token == string::npos ? string::npos : pos_end_token-pos); 
     // if the token is a word, save it to the list of words. 
     // if it's a space, save it to the list of spaces 
     if(is_char) 
      words.push_back(token); 
     else 
      spaces.push_back(token); 
     // move on to the next token 
     pos = pos_end_token; 
    } 

    // construct the new string using stringstream 
    stringstream ss; 
    // walk through both the list of spaces and the list of words, 
    // keeping in mind that there may be more words than spaces, or vice versa 
    // construct the new string by first copying the word, then the spaces 
    strings::const_reverse_iterator it_w = words.rbegin(); 
    strings::const_iterator it_s = spaces.begin(); 
    while(it_w != words.rend() || it_s != spaces.end()) 
    { 
     if(it_w != words.rend()) 
      ss << *it_w++; 
     if(it_s != spaces.end()) 
      ss << *it_s++; 
    } 

    // pull a `string` out of the results & dump it 
    string reversed = ss.str(); 
    cout << "Input: '" << test_string << "'" << endl << "Output: '" << reversed << "'" << endl; 

} 
+0

Спасибо за это решение! Есть небольшая ошибка: попробуйте использовать строку, начинающуюся с нескольких пробелов, чтобы перевернуть. Я попытался переписать этот код, чтобы уменьшить потребление памяти (нет необходимости хранить векторы строк, достаточно векторов позиций). Это моя смутная попытка переписать код: http://ideone.com/2uw9e. – ovgolovin

0

Слишком строгая строка stl не реализует push_front. Тогда вы можете сделать это с помощью transform().

#include <string> 
#include <iostream> 
#include <algorithm> 

class push_front 
{ 
public: 
    push_front(std::string& s) : _s(s) {}; 
    bool operator()(char c) { _s.insert(_s.begin(), c); return true; }; 
    std::string& _s; 
}; 

int main(int argc, char** argv) 
{ 

    std::string s1; 
    std::string s("Now is the time for all good men"); 
    for_each(s.begin(), s.end(), push_front(s1)); 

    std::cout << s << "\n"; 
    std::cout << s1 << "\n"; 
} 

Сейчас настало время для всех хороших людей

ного Doog лла ROF Испустите EHT си Won

+0

-1 Это даже близко к тому, что задал ОП – pmg

2

Я бы перефразировать проблему таким образом:

  • Non -пространственные токены меняются на обратные, но сохраняют их первоначальный порядок
    • 5 не-пространственных токенов 'this', 'is', 'my', 'test', 'string' заменяется на 'string', 'test', 'my', 'is', 'this' ,
  • Космические жетоны остаются в исходном порядке
    • Пространственные лексемы ««, ««, ««, ««остается в первоначальном порядке между новым порядком некосмическими лексем.

Ниже приводится решение O (N) [N является длиной массива символов]. К сожалению, это не так, как хотелось бы OP, но он не использует дополнительный стек или очередь - он использует отдельный массив символов в качестве рабочего пространства.

Вот псевдо-код C-ish.

work_array = char array with size of input_array 
dst = &work_array[ 0 ] 

for(i = 1; ; i++) { 
    detect i’th non-space token in input_array starting from the back side 
    if no such token { 
     break; 
    } 
    copy the token starting at dst 
    advance dst by token_size 
    detect i’th space-token in input_array starting from the front side 
    copy the token starting at dst 
    advance dst by token_size 
} 

// at this point work_array contains the desired output, 
// it can be copied back to input_array and destroyed 
+0

+1 Хороший общий подход, хотя я бы разломил его, пока! NUL {1) сканирует размер следующего текстового блока 2) копирует текст в новый буфер 3) скопировать пространство пробелом}. Нет точки подсчета пробелов перед их копированием. –

0

Copy каждая строка в массиве и напечатать его в обратном порядке (i--)

int main() 
{ 
int j=0; 
string str; 
string copy[80]; 
int start=0; 
int end=0; 
cout<<"Enter the String :: "; 
getline(cin,str); 
cout<<"Entered String is : "<<str<<endl; 
for(int i=0;str[i]!='\0';i++) 
{ 
end=s.find(" ",start); 
if(end==-1) 
{ 
copy[j]=str.substr(start,(str.length()-start)); 
break; 
} 
else 
{ 
copy[j]=str.substr(start,(end-start)); 
start=end+1; 
j++; 
i=end; 
} 
} 

for(int s1=j;s1>=0;s1--) 
cout<<" "<<copy[s1]; 
} 
Смежные вопросы