2010-09-23 55 views
7

Tôi đang cố đảo ngược thứ tự các từ trong một câu bằng cách duy trì các khoảng trắng như dưới đây.Đảo ngược chuỗi trong C++

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

tôi đã làm trong từng bước cách như,

[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 

Có phương pháp nào khác để làm điều này? Có thể thực hiện bước cuối cùng tại chỗ không?

+3

Tôi rất thích biết business logic đằng sau này ... – jcolebrand

+0

@drachenstern Vâng, bạn có thể cần các thuật toán tương tự khi hiển thị văn bản bidi. – ybungalobill

+0

Ý bạn là gì "Bạn cũng có thể thực hiện bước cuối cùng tại chỗ" không? Những gì bạn có đã làm mọi thứ tại chỗ. Bạn đang nói về "bước cuối cùng"? – AnT

Trả lời

5

Cách tiếp cận của bạn là tốt. Nhưng cách khác bạn cũng có thể làm:

  • Giữ quét các đầu vào cho lời nói và gian
  • Nếu bạn tìm thấy một từ đẩy nó vào stack S
  • Nếu bạn tìm không gian (s) enqueue số không gian vào một hàng đợi Q

Sau này được thực hiện sẽ có N từ trên stack và N-1 số trong q ueue.

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

Đối với những lời từ đầu đến từ trung tâm chuyển từ n với chiều dài từ - n đầu tiên sử dụng một chức năng phân chia và sau đó làm chuyển

-1

tôi nghĩ rằng tôi muốn chỉ tokenize (strtok hoặc CString :: Tokanize) các chuỗi sử dụng ký tự khoảng trắng. Đẩy các chuỗi vào một vectơ, kéo chúng trở lại theo thứ tự ngược lại và nối chúng với một khoảng trống ở giữa.

+0

với một chút dọn dẹp để logic của bạn về việc tìm kiếm các không gian trung gian (phải giữ lại thứ tự không gian ban đầu) Tôi sẽ chỉ này – jcolebrand

+0

Làm thế nào điều này sẽ duy trì nhiều không gian giữa các từ, như trong ví dụ của mình giữa "thử nghiệm" và "chuỗi"? – KeithS

+0

-1: strtok là zomg xấu và CString không phải là tiêu chuẩn C++ –

1

Mã giả này giả định bạn không kết thúc chuỗi ban đầu với khoảng trống, mặc dù có thể được sửa đổi phù hợp cho điều đó.

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

Tất cả các giải pháp strtok không hoạt động cho ví dụ của bạn, xem ở trên. Hãy thử cách này:

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

Nó có vẻ hơi điên rồ khi cần gọi và tự do làm điều gì đó đơn giản về mặt khái niệm? Và bạn đang sửa đổi chuỗi đầu vào? –

+0

Vâng, tôi sửa đổi nó. Bạn không biết sự khác biệt giữa ? – user411313

+0

-1: nó không hoạt động; +0.5 nó biên dịch (http://codepad.org/8pQGNta3) - tổng số làm tròn lên: 0 – pmg

2

Đây là một cách tiếp cận.

Tóm lại, hãy xây dựng hai danh sách mã thông báo bạn tìm thấy: một cho các từ và một thẻ khác cho dấu cách. Sau đó, mảnh với nhau một chuỗi mới, với các từ theo thứ tự ngược lại và các không gian theo thứ tự chuyển tiếp.

#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

Cảm ơn bạn đã giải pháp này! Có một lỗi nhỏ: chỉ cần thử sử dụng một chuỗi bắt đầu với một vài khoảng trống để đảo ngược. Tôi đã cố gắng để revrite mã này để giảm tiêu thụ bộ nhớ (không cần phải giữ vectơ của dây, chỉ cần vectơ của các vị trí sẽ đủ). Đây là nỗ lực mơ hồ của tôi để viết lại mã: http://ideone.com/2uw9e. – ovgolovin

0

Chuỗi stl quá xấu không triển khai push_front. Sau đó, bạn có thể làm điều này với 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"; 
} 

Bây giờ là thời gian cho tất cả những người đàn ông tốt

nem doog LLA ROF Emit EHT Si Won

+0

-1 Đó không phải là ngay cả những gì OP hỏi – pmg

2

tôi sẽ nói lại vấn đề theo cách này:

  • Non mã thông báo không gian bị đảo ngược, nhưng vẫn giữ nguyên thứ tự ban đầu của chúng
    • 5 thẻ không gian 'this', 'is', 'my', 'test', 'string' được đảo ngược thành 'string', 'test', 'my', 'is', 'this' .
  • tokens Space vẫn theo thứ tự ban đầu
    • Các thẻ không gian ‘‘, ‘‘, ‘‘, ‘‘vẫn theo thứ tự ban đầu giữa trật tự mới của thẻ phi không gian.

Sau đây là giải pháp O (N) [N là độ dài mảng char]. Thật không may, nó không phải là tại chỗ như OP muốn, nhưng nó không sử dụng thêm stack hoặc hàng đợi hoặc - nó sử dụng một mảng ký tự riêng biệt như một không gian làm việc.

Đây là mã giả 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 Cách tiếp cận chung tốt, mặc dù tôi muốn chia nhỏ nó trong khi NUL {1) quét kích thước của khối văn bản tiếp theo 2) sao chép văn bản vào bộ đệm mới 3) sao chép không gian theo không gian}. Không có điểm đếm các không gian trước khi sao chép chúng. –

0

Sao chép mỗi chuỗi trong mảng và in nó theo thứ tự ngược (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]; 
}