【问题标题】:Finding unique elements in an string array in C在C中的字符串数组中查找唯一元素
【发布时间】:2011-02-17 18:28:42
【问题描述】:

C 对字符串的处理让我很困扰。我脑子里有个这样的伪代码:

char *data[20]; 

char *tmp; int i,j;

for(i=0;i<20;i++) {
  tmp = data[i]; 
  for(j=1;j<20;j++) 
  {
    if(strcmp(tmp,data[j]))
      //then except the uniqueness, store them in elsewhere
  }
}

但是当我对此进行编码时,结果很糟糕。(我处理了所有的内存内容,小事情等)问题显然出在第二个循环中:D。但我想不出任何解决方案。如何在数组中找到唯一的字符串。

输入示例:输入 abc def abe abc def deg 唯一的:应该找到 abc def abe deg。

【问题讨论】:

  • 首先对数组进行排序会让您走得更远。然后只是遍历字符串,如果当前字符串与之前的字符串不同,它是唯一的,你可以将它存储在其他地方。
  • 问题是我需要确切的位置。你知道这样:输入:abc def abe abc def deg 输入了唯一的:abc def abe deg 如果我对数组进行排序,我将得到这样的唯一的:abc abe def deg 这不是我想要的我需要的位置也是。
  • 然后在您排序的初始数组中创建一个指针数组或数组索引数组,而不是对初始数组进行排序。
  • 他也可以尝试构建一个哈希表,尽管只有 20 个左右的项目,这肯定是矫枉过正。

标签: c arrays string strcmp


【解决方案1】:

您可以使用qsort 强制重复项彼此相邻。排序后,您只需比较相邻条目即可找到重复项。结果是 O(N log N) 而不是(我认为) O(N^2)。

这是没有错误检查的 15 分钟午餐时间版本:

  typedef struct {
     int origpos;
     char *value;
  } SORT;

  int qcmp(const void *x, const void *y) {
     int res = strcmp( ((SORT*)x)->value, ((SORT*)y)->value );
     if ( res != 0 )
        return res;
     else
        // they are equal - use original position as tie breaker
        return ( ((SORT*)x)->origpos - ((SORT*)y)->origpos );
  }

  int main( int argc, char* argv[] )
  {
     SORT *sorted;
     char **orig;
     int i;
     int num = argc - 1;

     orig = malloc( sizeof( char* ) * ( num ));
     sorted = malloc( sizeof( SORT ) * ( num ));

     for ( i = 0; i < num; i++ ) {
        orig[i] = argv[i + 1];
        sorted[i].value = argv[i + 1];
        sorted[i].origpos = i;
        }

     qsort( sorted, num, sizeof( SORT ), qcmp );

     // remove the dups (sorting left relative position same for dups)
     for ( i = 0; i < num - 1; i++ ) {
        if ( !strcmp( sorted[i].value, sorted[i+1].value ))
           // clear the duplicate entry however you see fit
           orig[sorted[i+1].origpos] = NULL;  // or free it if dynamic mem
        }

     // print them without dups in original order
     for ( i = 0; i < num; i++ )
        if ( orig[i] )
           printf( "%s ", orig[i] );

     free( orig );
     free( sorted );
  }

【讨论】:

  • 我知道这一点。我不想要一个排序数组并完成这项工作。我需要这些你知道的位置。你知道这样:输入:abc def abe abc def deg 输入了唯一的:abc def abe deg 如果我对数组进行排序,我将得到这样的唯一的:abc abe def deg 这不是我想要的我需要的位置也是。
  • 我认为 Mark 实际上并不知道,因为您在问题中没有提到这一点。
  • 这就是我问这个的原因:)。我已经知道排序和检查相邻元素。但这并不能解决我的问题。
  • 按照 WhirlWind 的建议对索引数组进行排序应该可以解决这个问题。它会保持原始订单不变。
【解决方案2】:

可能你的测试是 if (strcmp (this, that)) 如果两者不同就会成功? !strcmp 可能是你想要的。

【讨论】:

    【解决方案3】:
    char *data[20];
    int i, j, n, unique[20];
    
    n = 0;
    for (i = 0; i < 20; ++i)
    {
        for (j = 0; j < n; ++j)
        {
            if (!strcmp(data[i], data[unique[j]]))
               break;
        }
    
        if (j == n)
            unique[n++] = i;
    }
    

    如果我做对了,每个唯一字符串的第一次出现的索引应该在 unique[0..n-1] 中。

    【讨论】:

    • 这看起来很有趣,我会试试这个。
    【解决方案4】:

    为什么要从 1 开始第二个循环?

    你应该从 我+1。即

    for(j=i+1;j<20;j++) 
    

    如果列表是这样的

    abc
    def
    abc
    abc
    lop
    

    然后

    当 i==4

    tmp="lop"

    然后第二个循环开始,从 1 到 19。这意味着它在一个阶段也将获得 4 的值,然后

    data[4],即“lop”,将与 tmp 相同。所以虽然“lop”是唯一的,但它会被标记为重复。

    希望对您有所帮助。

    【讨论】:

    • 这绝对不是主要问题。还是 O(n^2)
    • 这真的取决于你对“主要问题”的定义。这个答案已经确定了一个比性能问题更严重的正确性问题。
    • @caf 和@Terry:实际上,在他的问题中我没有找到任何与性能相关的内容。他的报价“但是当我编码时结果很糟糕。(我处理了所有的内存东西,小东西等)问题显然出在第二个循环中:D。但我想不出任何解决方案。我如何找到唯一的字符串在一个数组中。”所以我只关注他的代码为什么不起作用。后来,从其他答案和 cmet 中,我意识到讨论已经采取了不同的形式。
    【解决方案5】:

    多想想你的问题——你真正想做的是查看以前的字符串,看看你是否已经看过它。因此,对于每个字符串 n,将其与字符串 0n-1 进行比较。

    print element 0 (it is unique)
    for i = 1 to n
      unique = 1
      for j = 0 to i-1 (compare this element to the ones preceding it)
        if element[i] == element[j]
           unique = 0
           break from loop
      if unique, print element i
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多