2010-09-23 19 views
7

Estoy tratando de invertir el orden de las palabras en una oración manteniendo los espacios como a continuación.Inversión de cadena en C++

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

lo hice en una manera paso a paso como,

[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 

¿Hay algún otro método para hacer esto? ¿También es posible hacer el último paso en el lugar?

+3

Me gustaría saber la lógica de negocio detrás de esto ... – jcolebrand

+0

@drachenstern Bueno, puede necesita algoritmos similares cuando se renderiza texto bidi. – ybungalobill

+0

¿Qué quiere decir con su "¿También es posible dar el último paso en el lugar"? Lo que tienes ya está haciendo todo en el lugar. ¿De qué "último paso" estás hablando? – AnT

Respuesta

5

Su enfoque está bien. Pero, alternativamente, también se puede hacer:

  • Mantener el escaneo de la entrada para las palabras y espacios
  • Si encuentra una palabra empujarla en la pila S
  • Si encuentra el espacio (s) poner en cola el número de espacios en una cola Q

Después de esto se hace habrá N palabras en la pila y N-1 números en la q ueue

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

Para las palabras de primero en las palabras centrales interruptor de canal n con la longitud de la palabra - n primer uso de una función de división y luego hacer la conmutación

-1

creo que me acaba de tokenize (strtok o CString :: Tokanize) del cadena usando el carácter espacio Inserta las cuerdas en un vector, luego retírelas en orden inverso y concatenarlas con un espacio intermedio.

+0

con un poco de limpieza a su lógica para encontrar los espacios intermedios (tiene que conservar el orden original del espacio) Me gustaría simplemente – jcolebrand

+0

¿Cómo mantendría esto espacios múltiples entre palabras, como en su ejemplo entre "prueba" y "cadena"? – KeithS

+0

-1: strtok es zomg malo y CString no es Estándar C++ –

1

Este pseudocódigo asume que no finaliza la cadena inicial con un espacio en blanco, aunque también se puede modificar adecuadamente para eso.

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

Todas las soluciones strtok no funcionan para su ejemplo, consulte más arriba. Pruebe esto:

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

¿No parece un poco loco necesitar calloc y tener la libertad de hacer algo tan conceptualmente simple? ¿Y estás modificando la cadena de entrada? –

+0

Sí, lo estoy modificando. ¿No sabes la diferencia entre y ? – user411313

+0

-1: no funciona; +0.5 compila (http://codepad.org/8pQGNta3) - total redondeado: 0 – pmg

2

Aquí hay un enfoque.

En resumen, crea dos listas de tokens que encuentres: una para las palabras y otra para los espacios. Luego, junte una nueva cuerda, con las palabras en orden inverso y los espacios en orden de avance.

#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

¡Gracias por esta solución! Hay un pequeño error: simplemente intente usar una cadena que comience con unos pocos espacios para revertir. Traté de revritar este código para reducir el consumo de memoria (no hay necesidad de mantener vectores de cadenas, basta con los vectores de las posiciones). Este es mi vago intento de reescribir el código: http://ideone.com/2uw9e. – ovgolovin

0

Demasiado malo stl string no implementa push_front. Entonces podrías hacer esto con 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"; 
} 

Ahora es el momento de que todos los hombres buenos

nem doog lla ROF emiten EHT Si Won

+0

-1 Eso ni siquiera está cerca de lo que OP pidió – pmg

2

Me gustaría reformular el problema de esta manera:

  • no -los tokens de espacio se invierten, pero conserva su orden original
    • Los 5 tokens no espaciales 'this', 'is', 'my', 'test', 'string' se invierten a 'string', 'test', 'my', 'is', 'this' .
  • fichas Espacio permanecen en el orden original
    • Las fichas de espacio ‘‘, ‘‘, ‘‘, ‘‘se mantiene en el orden original entre el nuevo orden de las fichas no espaciales.

que sigue es una solución de O (N) [N es la longitud de matriz de caracteres]. Desafortunadamente, no está en su lugar como OP quería, pero tampoco utiliza pila o cola adicionales: utiliza una matriz de caracteres separada como espacio de trabajo.

Aquí hay un pseudo código 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 Buen enfoque general, aunque lo dividiría en while! NUL {1) escanear para el tamaño del siguiente bloque de texto 2) copiar texto en el nuevo buffer 3) copia espacio por espacio}. No tiene sentido contar los espacios antes de copiarlos. –

0

copiar cada cadena de la matriz e imprimirlo en orden inverso (yo--)

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]; 
} 
Cuestiones relacionadas