【问题标题】:Print all elements in an array just once in C?在C中只打印一次数组中的所有元素?
【发布时间】:2021-05-02 18:24:29
【问题描述】:

我在 C 中创建了一个数组,我知道如何打印数组中的每个元素,但不知道如何不打印重复的元素,或者更准确地说,就像我在标题中问的那样,我怎样才能一次打印所有元素?

例如我的数组是:[a b c d a a b d c c]

我想这样打印:[a b c d]

我认为我应该使用 forwhile 循环,但我不知道如何。我已经考虑了几个小时并做了一些研究,但找不到任何有价值的东西。

【问题讨论】:

  • 在打印之前对数组进行排序以使其更容易
  • @pmg 这种情况下是可以的,但是当输入例如[d b c a c b a a]时应该输出什么?
  • 输出顺序重要吗?
  • 我会遍历所有元素。对于每个元素,循环遍历前面的元素以查看它是否重复。如果不是,请打印它。是 O(N^2),但如果列表很小也没关系。
  • 如果数组元素的可能值的数量很少(例如,当值只有一个字节时),可以使用一个表来检查该值是否在之前(重复)或不是。

标签: arrays c loops printf unique


【解决方案1】:

你来了。

#include <stdio.h>

int main(void) 
{
    char a[] = { 'a', 'b', 'c', 'd', 'a', 'a', 'b', 'd', 'c', 'c' };
    const size_t N = sizeof( a ) / sizeof( *a );
    
    for ( size_t i = 0; i < N; i++ )
    {
        size_t j = 0;
        
        while ( j != i && a[j] != a[i] ) ++j;
        
        if ( j == i ) printf( "%c ", a[i] );
    }
    
    putchar ( '\n' );
    
    return 0;
}

程序输出是

a b c d 

或者例如,如果您有一个包含字符串的字符数组,则可以通过以下方式实现相同的方法。

#include <stdio.h>

int main(void) 
{
    char s[] = { "abcdaabdcc" };

    for (const char *p = s; *p != '\0'; ++p )
    {
        const char *prev = s;
        
        while ( prev != p && *prev != *p ) ++prev;
        
        if ( prev == p ) printf( "%c ", *p );
    }
    
    putchar ( '\n' );
    
    return 0;
}

程序输出和上图一样就是

a b c d 

【讨论】:

  • 非常感谢。但是我的问题是我编码课练习论文的一部分(别担心,我没有被注意到。我没有作弊。)而且我不应该使用我没有学过的符号。那么,是否可以在没有const charconst size_t 的情况下编写代码?
  • @Efe 例如,您可以使用 int 类型而不是 size_t,并且可以删除限定符 const。
【解决方案2】:

由于数组是一个包含小写字母的 char 数组,因此几乎没有不同的值。因此,您可以创建一个表格(也称为另一个数组)来跟踪已打印的值。

喜欢:

#define MAX ('z' - 'a' + 1)  // Calculate the number of unique elements

int already_printed[MAX] = { 0 };       // Mark all chars as "not printed"
for (i = 0; i < SIZE_OFF_ARRAY; ++i)
{
    if (already_printed[array[i] - 'a'] == 0)   // If NOT printed yet
    {
        printf("%c\n", array[i]);               // Print it and
        already_printed[array[i] - 'a'] = 1;    // mark it as printed
    }
}

这为您提供了一个简单的 O(N) 解决方案。在处理大型数组时,拥有 O(N) 解决方案对性能很重要。

注意:此解决方案假定所有数组元素都在 'a''z'(都包括在内)之间,但可以轻松扩展以支持更广泛的范围。

【讨论】:

    【解决方案3】:

    一个简单的方法:

    #include <stdio.h>
    
    int main() {
    
        int ascii[128] = { 0 };
        char input[] = "abcdaabdcc";
        
        for(int i = 0; input[i]; i++) {
            
            ++ascii[(int)input[i]];
        }
        
        for(int i = 0; i < 128; i++) {
            
            if( ascii[i] ) printf("%c ", i);
        }
        
        return 0;
    }
    

    数组 ascii 用于跟踪 128 个非负值 ascii 字符中每个字符的频率(例如,'a' 为 97,'0' 为 48)。然后如果一个字符的频率不为0,就打印这个字符。

    【讨论】:

      【解决方案4】:

      我不确定数组中元素的类型是什么,但我们假设它是 C 可以“本机”比较的某种类型。然后概念上简单的解决方案是对数组进行排序,并且打印它跳过重复项。排序将确保重复项相邻。这种方法在大多数情况下都会表现良好。

      首先,让我们设置一些特定于元素类型的辅助函数。如果您只想处理 char 类型,则可以删除 assign 函数,但无论如何编译器都会内联它。

      #include <stdlib.h>
      #include <stdio.h>
      
      // You can adapt the element type per your requirements
      typedef char ElementType;
      
      // This function assigns the source value to the destination:
      // it does what *dst = *src would do.
      static inline void assign(void *dst, const void *src)
      {
          *(ElementType*)dst = *(const ElementType*)src;
      }
      
      // This is the "spaceship" comparison operator (<=> in C++) that
      // merges less-than, equal, and more-than comparisons into one.
      int compare(const void *l, const void *r) 
      {
          const ElementType *L = l;
          const ElementType *R = r;
          if (*L < *R) return -1;
          if (*L > *R) return 1;
          return 0;
      }
      
      void print_element(const ElementType *el) { printf("%c", *el); }
      

      由于我们计划对数组进行排序,我们需要先复制它——毕竟,数组的“打印机”不应该修改它。这样的修改在小程序中是可以的,但只是一个坏习惯,因为如果你查看函数的名称,如print_unique,没有任何迹象表明它会修改它应该打印的数据:这不是打印通常的行为.这会出乎意料,而且很容易出错。

      如果可以修改源数组,则可以跳过复制操作:它的元素需要是非常量的,并且需要将 print_unique 函数名称更改为 sort_and_print_unique 之类的名称。

      ElementType *copy_array(const ElementType *src, const int count)
      {
          ElementType *copy = malloc(sizeof(ElementType) * count);
          if (!copy) abort;
          for (int i = 0; i < count; ++i)
              assign(copy + i, src + i);
          return copy;
      }
      

      现在是独特的元素打印机,并使用您提供的数据进行测试:

      void print_unique(const ElementType *data, int const count)
      {
          ElementType *copy = copy_array(data, count);
      
          qsort(copy, count, sizeof(ElementType), compare);
      
          printf("[");
          for (int i = 0; i < count; ++i) {
              if (i == 0 || compare(copy+i, copy+i-1) != 0) {
                  if (i != 0) printf(" ");
                  print_element(copy+i);
              }
          }
          printf("]\n");
      }
      
      int main() {
          const char array[] = "abcdaabdcc";
          print_unique(array, sizeof(array)/sizeof(*array) - 1);
      }
      

      输出:[a b c d]

      我上面提到的替代的修改实现是:

      void sort_and_print_unique(ElementType *data, int const count)
      {
          qsort(data, count, sizeof(ElementType), compare);
      
          printf("[");
          for (int i = 0; i < count; ++i) {
              if (i == 0 || compare(data+i, data+i-1) != 0) {
                  if (i != 0) printf(" ");
                  print_element(data+i);
              }
          }
          printf("]\n");
      }
      
      int main() {
          char array[] = "abcdaabdcc"; // note absence of const!
          sort_and_print_unique(array, sizeof(array)/sizeof(*array) - 1);
      }
      

      【讨论】:

        【解决方案5】:

        首先,对数组进行排序(例如使用qsort(3)),然后所有相等的元素将放在一起。然后在数组上进行一次传递,保存最后打印的元素...如果现在要打印的元素与最后打印的元素相同,只需跳过它并 continue; 到下一个。

        【讨论】:

          猜你喜欢
          • 2020-07-22
          • 2021-06-06
          • 2019-09-12
          • 1970-01-01
          • 2022-06-13
          • 2021-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多