【问题标题】:looking for a tuple matching algorithm寻找元组匹配算法
【发布时间】:2010-09-11 08:45:52
【问题描述】:

我需要在 C 中实现内存中的 tuple-of-strings 匹配功能。将有大量与不同操作关联的元组列表以及要与列表匹配的大量事件。

元组列表:

("one", "four")
("one")
("three")
("four", "five")
("six")    

event ("one", "two", "three", "four") 应该匹配列表项 ("one", "four") and ("one") and ("three") 但不匹配 ("四”,“五”)而不是(“六”)

我当前的方法使用所有元组字段值的映射作为使用该值的每个元组列表的键。有很多冗余的散列和列表插入。

有没有正确或经典的方法来做到这一点?

【问题讨论】:

    标签: c algorithm


    【解决方案1】:

    如果您只有少量可能的元组值,那么编写某种散列函数将它们转换为整数索引以便快速搜索是有意义的。

    如果有

    unsigned int hash(char *value){...}
    
    typedef struct _tuple {
        unsigned int bitvalues;
        void * data
    } tuple;
    
    tuple a,b,c,d;
    a.bitvalues  = hash("one");
    a.bitvalues |= hash("four");
    //a.data = something;
    
    unsigned int event = 0;
    //foreach value in event;
    event |= hash(string_val);
    
    // foreach tuple
    if(x->bitvalues & test == test)
    {
         //matches
    }
    

    如果有太多的值来做位掩码解决方案,你可以有一个链表数组。浏览事件中的每个项目。如果项目与 key_one 匹配,则使用第一个键遍历元组并检查第二个键的事件:

    typedef struct _tuple {
        unsigned int key_one;
        unsigned int key_two;
        _tuple *next;
        void * data;
    } tuple;
    
    tuple a,b,c,d;
    a.key_one = hash("one");
    a.key_two = hash("four");
    
    tuple * list = malloc(/*big enough for all hash indexes*/
    memset(/*clear list*/);
    
    //foreach touple item
    if(list[item->key_one])
       put item on the end of the list;
    else
       list[item->key_one] = item;
    
    
    //foreach event
       //foreach key
          if(item_ptr = list[key])
            while(item_ptr.next)
               if(!item_ptr.key_two || /*item has key_two*/)
                  //match
               item_ptr = item_ptr.next;
    

    这段代码没有经过任何测试,可能有很多小错误,但你应该明白这一点。 (已纠正的一个错误是元组匹配的测试条件)


    如果事件处理速度是最重要的,那么迭代所有构造的元组,计算出现次数并可能重新排序每个元组的键一/键二,这样最独特的值是有意义的首先列出。

    【讨论】:

    • thx,对于位掩码来说太多了,但第二个解决方案,key_one(s) 列表,解决了我自己的一个大问题,即我针对同一个事件多次测试一些元组。
    • 因为我主要关心的是限制我针对事件测试的元组数量,所以我将实施第二种方法的变体。变化是我希望 key_one 成为元组中最独特的部分。我会测试计算这个的开销是否有帮助或有伤害。谢谢。
    【解决方案2】:

    一种可能的解决方案是为每个单词分配一个唯一的素数。

    然后,如果您将每个元组中的单词相乘,那么您将得到一个表示列表中单词的数字。

    将一个列表除以另一个,如果得到整数余数,则一个列表包含在另一个列表中。

    【讨论】:

      【解决方案3】:

      我不知道任何经典或正确的方法来做到这一点,所以这就是我要做的:P

      您似乎想使用集合论术语来确定 A 是否是 B 的超集。一种方法是对 A 和 B 进行排序,然后对 A 和 B 执行合并排序操作,即尝试找出 A 中的值在 B 中的位置。 B 的那些也在 A 中的元素将具有重复项,而其他元素则不会。因为 A 和 B 都已排序,所以这应该不会太可怕。

      例如,您取 B 的第一个值,然后遍历 A,直到在 A 中找到它的重复项。然后您取 B 的第二个值,并从您之前离开的地方开始遍历 A。如果您到达 A 的末尾但没有找到匹配项,则 A 不是 B 的超集,并且您返回 false。

      如果这些元组可以保持排序,那么排序成本只会产生一次。

      【讨论】:

        【解决方案4】:

        如果您有少量可能的字符串,您可以为每个字符串分配一个索引并使用位图。这样一个简单的按位会告诉你是否有重叠。

        如果这不切实际,您的倒排索引设置可能会难以匹配速度,尤其是如果您只需要构建一次。 (元组列表在运行时会改变吗?)

        【讨论】:

        • 谢谢。是的,该列表在运行时被修改。可能的字符串不受限制。
        【解决方案5】:
            public static void Main()
            {
                List<List<string>> tuples = new List<List<string>>();
        
                string [] tuple = {"one", "four"};
                tuples.Add(new List<string>(tuple));
        
                tuple = new string [] {"one"};
                tuples.Add(new List<string>(tuple));
        
                tuple = new string [] {"three"};
                tuples.Add(new List<string>(tuple));
        
                tuple = new string[]{"four", "five"};
                tuples.Add(new List<string>(tuple));
        
                tuple = new string[]{"six"};
                tuples.Add(new List<string>(tuple));
        
                tuple = new string[] {"one", "two", "three", "four"};
        
                List<string> checkTuple = new List<string>(tuple);
        
                List<List<string>> result = new List<List<string>>();
        
                foreach (List<string> ls in tuples)
                {
                    bool ok = true;
                    foreach(string s in ls)
                        if(!checkTuple.Contains(s))
                        {
                            ok = false;
                            break;
                        }
                    if (ok)
                        result.Add(ls);
                }
            }
        

        【讨论】:

        • 问题是针对 C 解决方案。不是 C++。
        猜你喜欢
        • 1970-01-01
        • 2017-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-04
        • 1970-01-01
        • 2019-08-31
        相关资源
        最近更新 更多