2010-05-13 4 views
1

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

Например:

Если вход вводится б а с с D T

Результат должен быть: б а в г т в точном состоянии, что ввод введенного.

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


Для тех, кто готов ответить на этот вопрос, я хотел бы добавить определенную информацию.

char** finduni(char *words[100],int limit) 
{ 
// 
//Methods here 
// 
} 

- это моя функция. Массив, дубликаты которого должны быть удалены и сохранены в другом массиве, - это слова [100]. Таким образом, процесс будет сделан на этом. Сначала я подумал о том, чтобы получить все элементы слов в другом массиве и отсортировать этот массив, но это не сработает после некоторых тестов. Просто напоминание для решателей :).

+0

Является ли это массивом 'char' как ваш пример?В этом случае просто сохраните массив из 256 булевых значений, указывающих, какие символы вы видели раньше. – Thomas

+0

Должно быть в порядке, хотя ... – Phil

+0

У меня есть несколько вопросов - вводится ли ввод 1 за раз, или все сразу? Является ли это массивом 'char' или каким-либо другим типом с более высокой границей? – Phil

ответ

0
  1. траверс по элементам массива - O(n) операции
  2. Для каждого элемента, добавить его к другому отсортированного массива
  3. Перед добавлением его в отсортированный массив, проверьте, если запись уже существует - O(log n) операции

Наконец, O(n log n) операция

+0

Согласно OP, новый массив должен поддерживать первоначальную сортировку. –

+0

Вы можете заменить отсортированный массив шагов 2 и 3. с помощью хешета, и вы получите амортизацию O (n) для всей операции. Это предполагает, что у вас есть хеш-функция над элементами, чтобы обмануть, но мы уже предполагали, что у нас был общий порядок, поэтому ... –

+0

@ Ник, возможно, MasterGaurav не объяснил это достаточно хорошо, но ey явно думает алгоритма, который сохраняет порядок от исходного массива (дублированные элементы представлены в массиве результатов в позиции их первого вхождения в исходном массиве) –

0

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

Если вы читаете элемент один за другим, вы можете отбросить элемент перед вставкой в ​​исходный массив, это может ускорить процесс.

+0

Можете ли вы объяснить, как вы ускоряетесь здесь? Расходы на поиск остаются именем .. best O (log n) для отсортированных –

+0

ребята парни :). Проблема здесь заключается в том, чтобы сделать работу на самом деле не сложной. Поэтому постарайтесь сосредоточиться на этом PLS. – LuckySlevin

0

Как отметил Томас в комментарии, если каждый элемент массива гарантированно ограничен ограниченным набором значений (например, char), вы можете достичь этого в O(n) времени.

  1. Держите массив 256 bool (или int, если ваш компилятор не поддерживает bool) или однако много различных дискретных значений могли бы быть в массиве. Инициализируйте все значения до false.
  2. Сканирование массива ввода один за другим.
  3. Для каждого элемента, если соответствующее значение в массиве bool равно false, добавьте его в выходной массив и установите значение массива bool равным true. В противном случае ничего не делайте.
+0

Проблема заключается в том, что массив не является массивом символов, это массив строк. – LuckySlevin

+0

Да, я вижу, вы добавили это сейчас. –

3

Ну, вот версия для char. Обратите внимание, что он не масштабируется.

#include "stdio.h" 
#include "string.h" 

void removeDuplicates(unsigned char *string) 
{ 
    unsigned char allCharacters [256] = { 0 }; 
    int lookAt; 
    int writeTo = 0; 
    for(lookAt = 0; lookAt < strlen(string); lookAt++) 
    { 
     if(allCharacters[ string[lookAt] ] == 0) 
     { 
     allCharacters[ string[lookAt] ] = 1; // mark it seen 
     string[writeTo++] = string[lookAt];  // copy it 
     } 
    } 
    string[writeTo] = '\0'; 
} 

int main() 
{ 
    char word[] = "abbbcdefbbbghasdddaiouasdf"; 
    removeDuplicates(word); 
    printf("Word is now [%s]\n", word); 
    return 0; 
} 

Ниже выход:

Word is now [abcdefghsiou] 

Это что-то вроде того, что вы хотите? Вы можете изменить метод, если между буквами есть пробелы, но если вы используете в качестве типов int, float, double или char *, этот метод не будет масштабироваться вообще.

EDIT

Я отвечал, а затем увидел ваше разъяснение, где это массив char *. Я обновлю метод.


Надеюсь, это не слишком много кода. Я адаптировал this QuickSort algorithm и в основном добавил к нему индексную память. Алгоритм O (n log n), поскольку 3 шага ниже являются аддитивными, и это худшая сложность двух из них.

  1. Сортируйте массив строк, но каждый своп должен также отражаться в массиве индексов. После этого этапа i-й элемент originalIndices содержит исходный индекс i-го элемента отсортированного массива.
  2. Удалите повторяющиеся элементы в отсортированном массиве, установив их в NULL и установив значение индекса в elements, что является самым высоким, что может быть.
  3. Сортируйте массив исходных индексов и убедитесь, что каждый своп отражен в массиве строк. Это возвращает нам исходный массив строк, за исключением того, что дубликаты находятся в конце, и все они - NULL.
  4. Для хорошей меры я возвращаю новое количество элементов.

Код:

#include "stdio.h" 
#include "string.h" 
#include "stdlib.h" 

void sortArrayAndSetCriteria(char **arr, int elements, int *originalIndices) 
{ 
    #define MAX_LEVELS 1000 
    char *piv; 
    int beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R; 
    int idx, cidx; 
    for(idx = 0; idx < elements; idx++) 
     originalIndices[idx] = idx; 
    beg[0] = 0; 
    end[0] = elements; 
    while (i>=0) 
    { 
     L = beg[i]; 
     R = end[i] - 1; 
     if (L<R) 
     { 
     piv = arr[L]; 
     cidx = originalIndices[L]; 
     if (i==MAX_LEVELS-1) 
      return; 
     while (L < R) 
     { 
      while (strcmp(arr[R], piv) >= 0 && L < R) R--; 
      if (L < R) 
      { 
       arr[L] = arr[R]; 
       originalIndices[L++] = originalIndices[R]; 
      } 
      while (strcmp(arr[L], piv) <= 0 && L < R) L++; 
      if (L < R) 
      { 
       arr[R] = arr[L]; 
       originalIndices[R--] = originalIndices[L]; 
      } 
     } 
     arr[L] = piv; 
     originalIndices[L] = cidx; 
     beg[i + 1] = L + 1; 
     end[i + 1] = end[i]; 
     end[i++] = L; 
     } 
     else 
     { 
     i--; 
     } 
    } 
} 

int removeDuplicatesFromBoth(char **arr, int elements, int *originalIndices) 
{ 
    // now remove duplicates 
    int i = 1, newLimit = 1; 
    char *curr = arr[0]; 
    while (i < elements) 
    { 
     if(strcmp(curr, arr[i]) == 0) 
     { 
     arr[i] = NULL; // free this if it was malloc'd 
     originalIndices[i] = elements; // place it at the end 
     } 
     else 
     { 
     curr = arr[i]; 
     newLimit++; 
     } 
     i++; 
    } 
    return newLimit; 
} 

void sortArrayBasedOnCriteria(char **arr, int elements, int *originalIndices) 
{ 
    #define MAX_LEVELS 1000 
    int piv; 
    int beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R; 
    int idx; 
    char *cidx; 
    beg[0] = 0; 
    end[0] = elements; 
    while (i>=0) 
    { 
     L = beg[i]; 
     R = end[i] - 1; 
     if (L<R) 
     { 
     piv = originalIndices[L]; 
     cidx = arr[L]; 
     if (i==MAX_LEVELS-1) 
      return; 
     while (L < R) 
     { 
      while (originalIndices[R] >= piv && L < R) R--; 
      if (L < R) 
      { 
       arr[L] = arr[R]; 
       originalIndices[L++] = originalIndices[R]; 
      } 
      while (originalIndices[L] <= piv && L < R) L++; 
      if (L < R) 
      { 
       arr[R] = arr[L]; 
       originalIndices[R--] = originalIndices[L]; 
      } 
     } 
     arr[L] = cidx; 
     originalIndices[L] = piv; 
     beg[i + 1] = L + 1; 
     end[i + 1] = end[i]; 
     end[i++] = L; 
     } 
     else 
     { 
     i--; 
     } 
    } 
} 

int removeDuplicateStrings(char *words[], int limit) 
{ 
    int *indices = (int *)malloc(limit * sizeof(int)); 
    int newLimit; 
    sortArrayAndSetCriteria(words, limit, indices); 
    newLimit = removeDuplicatesFromBoth(words, limit, indices); 
    sortArrayBasedOnCriteria(words, limit, indices); 
    free(indices); 
    return newLimit; 
} 

int main() 
{ 
    char *words[] = { "abc", "def", "bad", "hello", "captain", "def", "abc", "goodbye" }; 
    int newLimit = removeDuplicateStrings(words, 8); 
    int i = 0; 
    for(i = 0; i < newLimit; i++) printf(" Word @ %d = %s\n", i, words[i]); 
    return 0; 
} 
+0

читать первое сообщение чувак. – LuckySlevin

+0

Большое спасибо. На самом деле было бы достаточно, чтобы вы дали мне эту идею, и я мог бы прокомментировать эту идею. Спасибо за ваши старания. Я попробую это в кратчайшие сроки. – LuckySlevin

+0

Нет проблем. Прошло некоторое время с тех пор, как я использовал C, поэтому там могут быть угловые случаи, и это не самый DRY-код. Надеюсь, поможет! – Phil

0

Вы знаете, как это сделать для символьного типа, верно? Вы можете сделать то же самое со строками, но вместо использования массива bools (который является технически реализацией объекта «set»), вам придется моделировать «set» (или массив bools) с помощью линейного массива которые вы уже встречали. То есть у вас есть массив строк, которые вы уже видели, для каждой новой строки вы проверяете, находится ли она в массиве «видимых» строк, если она есть, то вы игнорируете ее (не уникальную), если она не находится в массиве, вы добавляете ее как для массива видимых строк, так и для вывода. Если у вас небольшое количество разных строк (ниже 1000), вы можете игнорировать оптимизацию производительности и просто сравнивать каждую новую строку со всем, что вы уже видели раньше.

С большим количеством строк (несколько тысяч), однако, вы должны оптимизировать вещи немного:

1) Каждый раз при добавлении новой строки в массив строк, которые вы уже видели, сортировать массив с алгоритмом сортировки вставки. Не используйте quickSort, потому что сортировка вставки обычно быстрее, когда данные сортируются почти.

2) При проверке, является ли строка в массиве, используйте двоичный поиск.

Если количество различных строк является разумным (т. Е. У вас нет миллиардов уникальных строк), этот подход должен быть достаточно быстрым.