2011-10-18 3 views
2

У меня есть фрагмент кода в C, который удаляет любой повторяющийся символ в строке. Но я делаю это в двух циклах и хотел бы, чтобы он оптимизировался до одного цикла.Как оптимизировать этот кусок кода В c

void removeDuplicates(char* ptr) 
{ 
int end = 1; 
int length = strlen(ptr); 
int current; 
int i; 
current = 1; 
for(end=1; end<length; end++) 
{ 
    for(i=0; i<end; i++) 
    { 
     if(ptr[end] == ptr[i]) 
     break; 
    } 
    if(i == end) 
    { 
     ptr[current] = ptr[i]; 
     current++; 
    } 
    } 
    ptr[current] = 0; 
} 

int main(int argc, char** argv) 
{ 
    char str[256] = {0,}; 
    gets(str); 
    removeDuplicates(str); 
    printf("%s\n", str); 
    return 1; 
} 

Как я могу сделать это в одной петле

+0

-1 для неаккуратного отступа и так много пробелов, что рядом с кодом есть полоса прокрутки. Опубликуйте комментарий, когда вы правильно отформатировали код, и я передумаю. –

+2

отправьте свой код на http://codereview.stackexchange.com/ – Constantinius

ответ

4

Вы можете сделать это в один проход с чем-то вроде:

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

int main (void) { 
    char str[] = "p123h12p97h62p32h"; // Input string. 
    int found[256];      // Assumes 8-bit char. 
    char *src, *dst;      // Source and destination pointers. 

    // Output initial value and set found flags to false. 

    printf ("Before: [%s]\n", str); 
    memset (found, 0, sizeof(found)); 

    // One loop, processing each source character in string. 

    for (src = dst = str; *src != '\0'; src++) { 
     // If not yet found, flag it found and transfer it, else do nothing. 

     if (!found[(unsigned int)(*src)]) { 
      found[(unsigned int)(*src)] = 1; 
      *dst++ = *src; 
     } 
    } 

    // Insert new end of string, then output it. 

    *dst = '\0'; 
    printf (" After: [%s]\n", str); 

    return 0; 
} 

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

src 
| 
v 
p123h12p97h62p32h 
^ 
| 
dst 

Указатель src продвигается вперед o каждая итерация цикла. Символ копируется из src в dst, а указатель dst продвигается, только если символ ранее не был замечен (с использованием массива found). Выход:

Before: [p123h12p97h62p32h] 
After: [p123h976] 

Обратите внимание на "assumes 8-bit char" комментарий - это прекрасно, когда вы знаете, что набор символов ASCII (или любой другой 8-битный набор символов), но она не может быть переносимым на более экзотические реализации. Вам просто нужно убедиться, что в массиве found достаточно элементов для всех ваших персонажей. Например, для 10-разрядного типа char потребуется 1024 элемента (210 = 1024).

+0

Еще два для петель! –

+0

Первый - это просто обнуление его флагового массива. Замените с помощью memset, если хотите. – GazTheDestroyer

+0

или просто используйте способ инициализации C .... Как я только что отредактировал. Кроме того, это две петли один за другим, все еще O (n), в то время как первый путь был петлей в цикле, который представляет собой O (n^2) –

1
void removeDuplicates(char* ptr) 
{ 
    int exists[256] = {0}; 
    int end; 
    int current = 0; 
    int length = strlen(ptr); 

    for(end = 0; end < length; end++) 
    { 
     if (exists[ptr[end]]) break; 

     exists[ptr[end]] = 1; 
     ptr[current++] = ptr[end]; 
    } 

    ptr[current] = '\0'; 
} 

int main(int argc, char** argv) 
{ 
    char str[256] = {0,}; 
    gets(str); 
    removeDuplicates(str); 
    printf("%s\n", str); 
    return 1; 
} 
1

Это то, что я изначально думал делать. Микро-оптимизация позволяет использовать меньше памяти для массива «видимый символ», иначе это та же идея, что и другие.

void removeDuplicates(char* src) { 
    // Bitfield to remember which chars we 've seen, assumes 8-bit char type 
    char bitfield[32] = { 0 }; // 32 * 8 = 256 bits 

    char* dest = src; // initialize "output" ptr 

    while(*src) { 
     // Bitfield manipulation 
     char ch = *src; 
     int pos = ch >> 3; // ch/8 
     int bit = ch & 0x7; // ch % 8 
     char mask = 1 << bit; 

     // If char seen for first time, mark and write to "output" 
     if(!(bitfield[pos] & mask)) { 
      bitfield[pos] |= mask; 
      *dest++ = ch; 
     } 
     ++src; 
    } 

    *dest = 0; // null terminator 
} 

See it in action.

+0

новая клонированная версия: http://ideone.com/wzWdF - этот использует 'fgets' для ввода и возвращает' 0'. – pmg

Смежные вопросы