2011-08-31 72 views
8

Tôi đang cố gắng để đảo ngược thứ tự các từ trong một câu tại chỗ, ví dụ:Đảo ngược thứ tự từ trong một chuỗi ở vị trí

này câu từ được đảo ngược.

trở thành

đảo ngược. là những từ câu này

Đây là những gì tôi có cho đến nay, hầu như hoạt động: tôi sử dụng hàm strrev để đảo ngược chuỗi, và sau đó là chức năng inprev để gửi mỗi từ với chức năng strrev cá nhân, để đảo ngược chúng quay trở lại hướng ban đầu, nhưng theo thứ tự đảo ngược. Gửi một con trỏ để bắt đầu và kết thúc hàm strrev có vẻ hơi ngớ ngẩn, nhưng nó cho phép cùng một hàm được sử dụng trong inprev(), gửi một con trỏ tới đầu và cuối của các từ riêng lẻ.

#include <stdio.h> 
#include <string.h> 

void strrev(char * start, char * end); 
void inprev(char * start); 

int main(void) 
{ 
    char str[] = "Foobar my friends, foobar"; 
    char * end = (str + strlen(str) -1); 
    puts(str); 
    strrev(str, end); 
    puts(str); 
    inprev(str); 

    puts(str); 

    return 0; 
} 

void strrev(char * start, char * end) 
{ 
    char temp; 

while (end > start) 
    { 
    temp = *start; 
    *start = *end; 
    *end = temp; 
     start++; 
     end--; 
    } 
} 

void inprev(char * start) 
{ 
    char * first = start; 
    char * spcpnt = start; 
    while (*spcpnt) 
    { 
     while (*spcpnt != ' ' && *spcpnt) 
      spcpnt++; 
     strrev(start, spcpnt-1);   // removing the -1 sends the space on the 
     start = spcpnt++;    // other side to be reversed, doesn't stop 
             // the problem. 

    } 

} 

Đây là kết quả:

Foobar bạn bè của tôi, foobar

raboof, sdneirf ym rabooF

foobarfriends, Foobar tôi

Vấn đề là việc thiếu một không gian cuối cùng ở cuối từ cuối cùng có nghĩa là mũ một không gian là mất tích giữa từ đó và preceeding một trong chuỗi cuối cùng, và thay vào đó được ném vào cuối của từ cuối cùng, đó là từ đầu tiên trong chuỗi ban đầu. Việc gửi không gian ở phía bên kia của từ chỉ di chuyển vấn đề ở nơi khác. Bất cứ ai có thể nhìn thấy một giải pháp?

+1

Bạn phải làm gì khi gặp phải không gian X? Chúng có thuộc về từ trước hay sau? – RedX

+0

+1 vấn đề tốt đẹp :). Nếu tôi có một chút thời gian, tôi sẽ cung cấp một giải pháp –

+0

Tôi đoán bạn không muốn làm cho chữ cái đầu tiên trở thành bức thư lớn, như ví dụ của bạn ... – imacake

Trả lời

5

Bạn chỉ cần di chuyển con trỏ start trong hàm inprev để bỏ qua khoảng trống giữa các từ. Vì điều này dường như là bài tập về nhà (đúng với tôi nếu tôi sai) Tôi sẽ chỉ nói rằng tất cả những gì bạn cần làm là di chuyển vị trí của một toán tử.

Nhưng, điều này tạo ra một vấn đề, cụ thể là, inprev thực hiện bộ đệm bị tràn vì tìm kiếm không bị chấm dứt đúng cách. Cách tốt hơn để làm điều đó là:

while not end of string 
    search for start of word 
    start = start of word 
    search for end of word 
    strrev (start, end) 

và điều đó cũng sẽ xử lý nhiều không gian. Ngoài ra, U + 0020 (ASCII 32, dấu cách) không phải là ký tự trắng duy nhất. Có các hàm thư viện chuẩn để kiểm tra các ký tự. Chúng nằm trong số <ctype.h> và bắt đầu bằng is..., ví dụ: isspace.

+0

Cảm ơn! Đã cập nhật câu hỏi ban đầu với thuật toán cố định của tôi. Không phải bài tập về nhà btw, nhìn thấy nó trong một buổi phỏng vấn câu hỏi phỏng vấn việc làm và nghĩ rằng tôi sẽ có một vết nứt ở đó cho vui. – Matt

+1

@Matt Vui lòng không sửa mã gốc trong câu hỏi! Điều đó làm cho câu hỏi vô dụng đối với bất kỳ ai đọc nó trong tương lai. Tôi sẽ khôi phục bản chỉnh sửa đó. – razlebe

+1

@Matt: để thêm vào nhận xét của razlebe, bạn có thể đăng mã được cập nhật dưới dạng câu trả lời, thay vì chỉnh sửa câu hỏi. – Skizz

0

Đã tìm ra giải pháp; đây là chức năng sửa đổi của tôi hoạt động tốt.

void inprev(char * str) 
{ 
    _Bool inword = 0; 
    char * wordend; 
    char * wordstart; 

    while(*str) 
    { 
     if(!isspace(*str) && (inword == 0)) 
     { 
      wordstart = str; 
      inword = 1; 
     } 
     else if (isspace(*str) && (inword == 1)) 
     { 
      wordend = str-1; 
      inword = 0; 
      strrev(wordstart, wordend); 
     } 

     str++; 
    } 

    if (*str == '\0') 
     strrev(wordstart, str-1); 

} 

char * wordend là không cần thiết vì bạn chỉ có thể chuyển str-1 vào hàm strrev, nhưng nó làm rõ hơn một chút những gì đang xảy ra.

1

Đôi khi mọi thứ trở nên dễ dàng hơn nếu bạn không sử dụng con trỏ nhưng bù trừ. Chức năng thư viện strspn() và strcspn() ít nhiều buộc bạn phải sử dụng bù trừ, và xử lý tình trạng cuối chuỗi khá độc đáo.

#include <stdio.h> 
#include <string.h> 

size_t revword(char *str); 
void revmem(void *ptr, size_t len); 

size_t revword(char *str) { 
size_t pos,len; 

for (pos=len=0; str[pos]; pos += len) { 
     len = strspn(str+pos, " \t\n\r"); 
     if (len) continue; 
     len = strcspn(str+pos, " \t\n\r"); 
     if (!len) continue; 
     revmem(str+pos, len); 
     } 
revmem(str, pos); 
return len; 
} 

void revmem(void *ptr, size_t len) 
{ 
size_t idx; 
char *str = (char*) ptr; 

if (len-- < 2) return; 

for (idx = 0; idx < len; idx++,len--) { 
     char tmp = str[idx]; 
     str[idx] = str[len]; 
     str[len] = tmp; 
     } 
} 

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

if (!argv[1]) return 0; 
revword(argv[1]); 
printf("'%s'\n", argv[1]); 

return 0; 
}                       
+0

Bạn có thể thêm một vài nhận xét để giải thích điều gì đang xảy ra không? Đó là một chút khó khăn để làm theo, ví dụ, những gì đang xảy ra trong chức năng revword. – Matt

+0

Vâng: trong vòng lặp, tôi đo chiều dài của khoảng trống liên tiếp (cuộc gọi strspn()) và bỏ qua nó. Sau đó tôi đo chiều dài của khoảng trắng * NON * liên tiếp (gọi strcspn()) và đảo ngược nó. Vào cuối vòng lặp, tôi có toàn bộ chiều dài của chuỗi tích lũy và đảo ngược toàn bộ chuỗi. – wildplasser

+0

Cool, chúc mừng người đàn ông! – Matt

0

Thuật toán sau đây được đặt tại chỗ và chạy theo 2 bước. Đầu tiên nó đảo ngược toàn bộ chuỗi. Sau đó, nó đảo ngược từng từ.

#include <stdio.h> 

void reverse(char *str, int len) 
{ 
    char *p = str; 
    char *e = str + len - 1; 

    while (p != e) { 
     *p ^= *e ^= *p ^= *e; 
     p++; 
     e--; 
    } 
} 

void reverse_words(char *str) 
{ 
    char *p; 

    // First, reverse the entire string 
    reverse(str, strlen(str)); 

    // Then, reverse each word 
    p = str; 
    while (*p) { 
     char *e = p; 
     while (*e != ' ' && *e != '\0') { 
      e++; 
     } 

     reverse(p, e - p); 
     printf("%.*s%c", e - p, p, *e); 

     if (*e == '\0') 
      break; 
     else 
      p = e + 1; 
    } 
} 

int main(void) { 
    char buf[] = "Bob likes Alice"; 
    reverse_words(buf); 
    return 0; 
} 
+0

Nếu 'len' là chẵn, hàm 'đảo ngược' sẽ gây ra sự phân đoạn. Hãy thử 'while (p

Các vấn đề liên quan