【问题标题】:sort and remove duplicates from int array in c排序并从c中的int数组中删除重复项
【发布时间】:2013-09-26 07:34:07
【问题描述】:

我正在学习C,并谈到了排序的话题。我在其中编写了一个comp() 函数并使用qsort 对int 的数组进行排序。现在对于下一个任务,我需要从数组中删除重复项。
是否可以同时排序和删除重复项?

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>    
int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };

int comp(const void * elem1, const void * elem2) {

    int f = *((int*) elem1);
    int s = *((int*) elem2);

    if (f > s) {    
        return 1;
    }    
    if (f < s) {    
        return -1;
    }    
    return 0;
}

void printIndexArray() {    
    int i = 0;    
    for (i = 0; i < 10; i++) {    
        printf("i is %d\n", indexes[i]);    
    }
}

int main() {    
    qsort(indexes, sizeof(indexes) / sizeof(int), sizeof(int), comp);    
    printIndexArray();    
    return 0;
}

【问题讨论】:

  • 你正在使用内置函数进行排序,编写你自己的函数。

标签: c arrays sorting


【解决方案1】:

由于您的号码已经排序,因此很容易消除骗局。在 C++ 中,它甚至内置为 std::unique:

http://en.cppreference.com/w/cpp/algorithm/unique

假设你想自己做,你可以像unique一样做:

int* unique (int* first, int* last)
{
  if (first==last) return last;

  int* result = first;
  while (++first != last)
  {
    if (!(*result == *first)) 
      *(++result)=*first;
  }
  return ++result;
}

【讨论】:

  • 上面的方法怎么用,刚开始学习,所以我的指点很好。你能帮我把独特的功能集成到我上面的代码中吗
  • 拨打unique(indexes, indexes + (sizeof(indexes) / sizeof(int)));
  • 顺便说一句,我建议制作一个宏或其他东西来获取数组大小。类似#define arrsize(x) (sizeof(x) / sizeof(x[0]))
  • 如果你有这样的宏,那就是unique(indexes, indexes + arrsize(indexes));
  • 如果此答案对您有用,请将其标记为答案-谢谢!
【解决方案2】:

是的

这可以通过mergesort 来实现。如果左右都相同,只需合并一个值

【讨论】:

    【解决方案3】:

    这是使用合并排序删除重复项的代码。这段代码的 sn-p 完成了删除工作:

    else if(a[p1] == a[p2])
    {
        merged[p] = a[p1];
        p1++;
        p2++;
    }
    

    这是迭代合并排序,而递归版本会更容易。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define min(a,b) (((a) < (b)) ? (a) : (b))
    
    int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };
    
    void merge(int *a, int s, int m, int e)
    {
        int p1 = s;
        int p2 = m + 1;
        int * merged = (int*)malloc(sizeof(int) * (e - s + 1));
        int p = 0;
        while(p1 < m + 1 && p2 < e + 1)
        {
            if(a[p1] > a[p2])
            {
                merged[p] = a[p2];
                p2++;
            }
            else if(a[p1] == a[p2])
            {
                merged[p] = a[p1];
                p1++;
                p2++;
            }
            else
            {
                merged[p] = a[p1];
                p1++;
            }
            p++;
        }
    
        while(p1 < m + 1)
        {
            merged[p++] = a[p1++];
        }
    
        while(p2 < e + 1)
            merged[p++] = a[p2++];
    
        int i;
        for(i = 0;i < (e -s+1); i++)
        {
            a[s + i] = merged[i];
        }
    
        free(merged);
    }
    
    void merge_sort(int *a, int n)
    {
        int width;
        for(width = 1; width < n; width = 2 * width)
        {
            int i;
            for(i = 0; i < n; i = i + 2 * width)
            {
                merge(a, i, min(i + width - 1, n - 1), min(i + 2 * width - 1, n - 1) );
            }
        }
    }
    
    void printIndexArray()
    {    
        int i = 0;    
        for(i = 0; i < 10; i++)
        {    
            printf("i is %d\n", indexes[i]);    
        }
    }
    
    int main()
    {
        merge_sort(indexes, sizeof(indexes) / sizeof(int) );
        printIndexArray();
        return 0;
    }
    

    【讨论】:

      【解决方案4】:
      #include <stdio.h>
      #include <stdlib.h>
      
      int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };
      
      size_t undup(int array[], size_t len)
      {
      size_t src,dst;
      
      if (!len) return 0;
      for (src=dst=1; src < len; src++) {
              if (array[dst-1] == array[src]) continue;
              array[dst++] = array[src];
              }
      return dst;
      }
      
      int comp(const void * elem1, const void * elem2) {
      
          int f = *((int*) elem1);
          int s = *((int*) elem2);
      
          if (f > s)     return 1;
          if (f < s)     return -1;
      
          return 0;
      }
      
      void printIndexArray(size_t len) {
          size_t i = 0;
          for (i = 0; i < len; i++) {
              printf("array[%zu] is %d\n", i, indexes[i]);
          }
      }
      
      int main() {
          size_t len = 10;
          printf("Before sort\n" );
          printIndexArray(len);
      
          qsort(indexes, sizeof indexes / sizeof indexes[0], sizeof indexes[0], comp);
          printf("After sort\n" );
          printIndexArray(len);
      
          len = undup(indexes,10);
          printf("After undup\n" );
          printIndexArray(len);
      
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        简短的回答是:是的。

        长答案是:总是有可能的,但执行此操作的复杂性在很大程度上取决于您使用的算法。

        更复杂的算法,如快速排序、慢速排序、桶排序和直基数排序不适合这种增强,因为它们依赖于连续数组中的数据,这可以隐式被分成子数组。因此,当您检测到重复项时,您无法轻易将其取出。同样,这是可能的,但对于初学者来说肯定不是问题。

        冒泡排序、插入排序和壳排序等不太复杂的就地算法使其相对容易:您只需将检测到的重复项之一替换为排序大于所有合法值的哨兵值,让它上升到顶部。在那之后,你只需要舀出哨兵值的精华就可以了。

        真正适合删除重复的算法是使用在此过程中增长/缩小的中间数组的算法;在这些情况下,当您检测到重复时,您可以缩小或跳过增长这些中间数组之一。候选者是合并排序和堆排序。

        但是,请注意,仅对数组进行排序并在第二个单独的步骤中消除重复项更为谨慎。为什么?因为消除重复增加了排序算法的内部循环的复杂性,在大多数相关情况下为 O(n*log(n))。但是从排序数组中消除重复是一个 O(n) 操作,使得拆分操作比融合操作更快。

        【讨论】:

          猜你喜欢
          • 2021-12-12
          • 2016-10-01
          • 2019-11-14
          • 2021-11-12
          • 2021-01-27
          • 2016-01-24
          • 2022-01-03
          • 1970-01-01
          • 2013-11-05
          相关资源
          最近更新 更多