【问题标题】:Efficient way to search a string in an array of string in C. (Case insensitive)在C中的字符串数组中搜索字符串的有效方法。(不区分大小写)
【发布时间】:2012-04-30 17:38:27
【问题描述】:

我正在处理一个项目(用 C 语言实现),我们需要维护一个特性或关键字列表。用户输入一个字符串。我们需要在存储的字符串数组中对该字符串进行不区分大小写的搜索。该列表目前包含 100 个字符串,并且可能会添加新字符串(一年左右 5 个字符串)。

我想知道存储这个数组的最佳方式,让搜索更有效率。

目前实现的解决方案如下:(我没有编译这段代码。这只是一个代码sn-p。)

    char **applist={ asdf , adgh, eftg , egty, ...} 
    char *user_input; // this string contains user entered string
    int id;
    switch(user_input[0])
    {
     case 'a':
     case 'A':
     switch(user_input[1]
     {
     case 's':
     case 'S':
     id=0
     break;

     case 'd':
     case 'D':
     id=1
     break;
     }
     break;
     case'e':
     case'E':
     switch(user_input[1])
     {
     case 'f':
     case 'F':
     id=2
     break;

     case 'g':
     case 'G':
     id=3
     break;
     }
     break;
     }
    if(stricmp(user_input,applist[id]))
    return id;
    else 
    return -1;

在实际代码中,applist 没有排序。随着新字符串被添加到 applist,我需要一种有效的方法来存储这个数组。

如果我存储按字母顺序排序的字符串,那么每次添加新字符串时,我都必须手动找到新字符串的正确位置。 (不是在运行时编译代码之前将新字符串添加到applist)

建议一种有效的方法。

编辑:我目前的方法导致代码更长但效率更高。但是这段代码不容易维护。我需要的是一种数据结构,它可以以与此相同的效率进行搜索,但代码更小。您建议的数据结构不应该有额外的开销。唯一的要求是高效搜索。以及一种在编译时轻松向数据结构添加元素的方法。在运行时排序不是我的要求,因为在编译时添加了新字符串(这是为了避免限制用户将任何新字符串添加到列表中)。

【问题讨论】:

    标签: c string search


    【解决方案1】:

    听起来这不是代码的性能关键位,在这种情况下,我建议使用 strcasestr 进行字符串比较。像这样存储关键字

    char *applist[] = {"abc", "def", "geh"}
    

    然后遍历它们并像这样将用户输入与 strcasestr 进行比较

    if (strlen(applist[id]) == strlen(user_input) && 
                strcasestr(applist[id], user_input) != NULL)
        return id;
    

    这种方法比使用复杂的数据结构更简洁和可维护。 如果您确实关心性能,请先实现此方法,进行一些时序测试,然后您可以决定是否需要更快的算法。

    【讨论】:

    • 实际上这是一项性能关键的任务。该函数被多次调用。不仅当用户输入查询时,它还会从一些配置文件中读取字符串并查找它是否匹配任何字符串。
    • +1 是迄今为止第一个理智的答案。引用 Rob Pike 的话:“如果 n 很小,花哨的算法就会很慢。而且 n 通常很小。”
    • @Ravichandra,您是否测试过它是否对性能至关重要,或者您只是假设?如果没有分析并看到它确实是一个问题,我不会尝试对其进行优化。
    • 我的算法做了 1 个字符串比较和几个字符比较(取决于字符串的唯一性)。我的字符串数组有许多长度相等的字符串。例如:22 个长度为 7 的字符串。
    • 如果用户输入一个长度为 7 的字符串,那么在最坏的情况下使用 ur 算法将进行 22 个字符串比较。(因为有 22 个大小为 7 的字符串)。这会降低性能。该函数被多次调用。因此,它对性能至关重要。
    【解决方案2】:

    在搜索字符串时,可以使用的最佳数据结构是 BST - 二叉搜索树 - http://en.wikipedia.org/wiki/Binary_search_tree。与使用arrayslists 时的O(n) 相比,最坏情况的搜索时间仅为O(log n)

    这是一个带有数字的示例代码(您可能需要用字符串更改它并使用strcmp):

    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <limits.h>
    
    typedef struct node {
            int data;
            struct node *left;
            struct node *right;
    } NODE;
    
    
    NODE * newnode (int data) 
    {
        NODE * n = NULL;
        if (n = (NODE *) malloc (sizeof (NODE))) {
            n->data = data;
            n->right = n->left = NULL;
        } else {
            printf("Error: unable to allocate memory \n");
        }
    
        return n;
    }
    
    
    NODE * insert (NODE * head, int data)
    {
        NODE * n;
    
        if (head == NULL)
            return newnode(data);
    
        if (head->data == data) {
            printf("Info: attempting to add duplicate element : %d\n", data);
            return head;
        }
    
        if (head->data < data)
            head->right = insert(head->right, data);
        else
            head->left = insert(head->left, data);
    
        return head;
    }    
    
    void inorder(NODE * node)
    {
            if (node == NULL) 
                    return;
    
            inorder(node->left);
            printf("%d ", node->data);
            inorder(node->right);
            return;
    }
    
    int lookup(NODE * head, int data)
    {
        if (head == NULL)
            return 0;
    
        if (head->data == data)
            return 1;
    
        if (head->data < data)
            return lookup(head->right, data);
        else
            return lookup(head->left, data);
    }
    
    void search(NODE * head, int data)
    {
        if (lookup(head, data)) {
            printf("found : %d \n", data);
        } else {
            printf("not found : %d \n", data);
        }
    
        return;
    }
    
    int main()
    {
        int sum = 35;
        NODE * root = NULL;
    
        root = insert(root, 20); 
        root = insert(root, 10); 
        root = insert(root, 22); 
        root = insert(root, 23); 
        root = insert(root, 24); 
        root = insert(root, 25); 
        root = insert(root, 10); 
        root = insert(root, 20); 
        root = insert(root, 30); 
        root = insert(root, 40); 
        root = insert(root, 50); 
        root = insert(root, 60); 
        inorder(root);  printf("\n");
    
        search(root, 10);
        search(root, 11);
        search(root, 13);
        search(root, 14);
    
        return 0;
    }
    

    OTOH,hast 表将为您提供恒定的搜索时间 O(1) - http://en.wikipedia.org/wiki/Hash_table

    【讨论】:

    • 我的算法做了 1 个字符串比较和几个字符比较(取决于字符串的唯一性)。但是您的方法在大多数情况下会导致超过 1 次的比较。字符串比较代价高昂。
    • 我的要求是在代码编译之前排序或添加新字符串,而不是在运行时。
    • @Ravichandra 我刚刚看到您对要求的新更新。正如您所提到的,嵌套的switch-case 只是不容易维护。而且,它不可扩展(例如,如果用户引入了一个新的关键字,而该关键字未包含在 switch-case 中,那么您需要对其进行编码)。 OTOH,您每年提到 100 个现有关键字和 5 个新关键字。因此,您不能期望开发人员/用户稍后手动对关键字进行排序。所以我的建议是处理代码中的所有内容 - 排序和搜索。
    • 正如我在回答中提到的,Hashtable 是理想的,但效率取决于哈希算法。
    • w.r.t 字符串比较 - 除非您使用哈希算法,否则您需要中继基本字符串比较库,例如 strcasecmp()
    【解决方案3】:

    一个好的数据结构可能是 TRIE:

    http://en.wikipedia.org/wiki/Trie

    看起来这就是您开始在代码中实现的内容。

    【讨论】:

    • 要么是那个,要么是一个哈希表。但目前的结构太可怕了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2011-12-20
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多