如何使用按字母顺序排序的列表中的相同第一个字母来获取一组名称?

时间:2011-02-11 23:37:04

标签: algorithm language-agnostic search

我想知道给出第一个字母的一组名字的最佳方法是什么。我正在使用的本应用程序是在javascript中,但有时我在另一种语言中遇到了类似的问题。我想到的一个想法是对特定字母的名称末尾进行二进制搜索,然后在开头做另一个二进制搜索。另一个想法是从给定字母的起始距离的比率和应用该比率来找到开始搜索的位置。例如,如果这封信是“e”,那么我将从列表的四分之一开始,然后进行某种搜索,看看我与我需要的信件有多接近。该程序将使用数百个名称,所以我真的不想只是做一个for循环并搜索整个事情。另外,我感兴趣的是什么样的算法呢?

5 个答案:

答案 0 :(得分:3)

您的方法都有其优点和缺点。二进制搜索提供完全 O(log(N))复杂度,第二种方法将给出大约 O(log(N)),这对于名称的均匀分布具有一定的优势对另一种分配可能不利。什么是更好的取决于您的需求。

我可以提出的一个重大改进是在创建名单时索引字符位置。使用首字母作为键来创建简单的哈希映射,并将值作为值开始。它将需要O(N),但只需要一次,然后您将在恒定时间内获得每个字母的确切位置。对于JavaScript,您可以这样做,例如,当您将数据加载到页面时,无论如何都要走到列表中。

答案 1 :(得分:1)

伙计我认为我们可以使用类似于count的方法。我们可以创建一个大小为26的数组。这个数组不是普通的数组,而是一个指向链表的指针数组,它具有以下结构。 / p>

结构节点 {  char * ptr; struct node * next; };

struct node * names [26]; //我们的阵列。

现在我们将在O(n)时间内扫描列表并对应于我们可以减去65的第一个字符(如果字母的ASCII值在65-90范围内)。。我正在减去65以便修复26大小的数组中的字母。 在每个位置,我们都可以创建一个链接列表,并可以在该位置存储相应的单词。

现在假设我们想要找到所有以D开头的字母,我们可以直接对数组位置3进行处理(不需要再次应用哈希函数),然后遍历链接列表,直到达到null为止。

我认为哈希所需的空间复杂度与上述相同,但是每当我们想要插入或搜索以相同字母开头的单词时,哈希也会涉及计算哈希函数。

答案 2 :(得分:0)

如果计划要对名称做一些事情(而不是只知道有多少名称),那么有必要扫描符合匹配第一个字母标准的名称。如果是这样,那么似乎在整个集合中对名字的二进制搜索是最快的方法。 “做某事”部分将涉及从二进制搜索找到的位置开始扫描名称。当读取的名称不再以给定的字母开头时,您就完成了。

答案 3 :(得分:0)

如果您有一组未分类的文件名,那么我建议使用以下算法:

1)创建两个变量: 1)当前找到的第一个字母(我将其称为 currentLetter 2)启动的文件名列表用这封信( currentFilenames
2)firstLetter = null
  currentFilenames = [] - 空列表或数组
3)迭代文件名。如果当前文件名以currentLetter开头,则将此文件名添加到currentFilenames。如果它以currentLetter之前的字母开头,则将currentLetter分配给新文件名的第一个字母,并创建一个新的currentFilenames列表,该列表仅包含一个当前文件名。

使用这样的算法,最后会有一个字母,该字母在字母表中排在第一位,从该字母开始的文件列表。

示例代码(尝试使用Javascript编写,但如果我写错了则不要责怪):

function GetFirstLetterAndFilenames(allFilenames) {
    var currentLetter = null;
    var currentFilenames = null;

    for (int i = 0; i < allFilenames.length ; i++) {
        var thisLetter = allFilenames[i][0];
        if (currentLetter == null || thisLetter < currentLetter) {
            currentLetter = thisLetter;
            currentFilenames = [allFilenames[i]];
        } else if (currentLetter == thisLetter) {
            currentFilenames.push(allFilenames[i]); 
        }
    }

    return new {lowestLetter = currentLetter, filenames = currentFilenames};
}

答案 4 :(得分:0)

名字有一种有趣的方式,就是不会在字母表上均匀分布,所以你可能不会通过预测到哪里来赢得胜利。

但是,将搜索平均缩减两个步骤的一种非常简单的方法如下:如果字母是从am,则二进制搜索下一个字母。然后从列表的开头二进制搜索到你刚刚找到的下一个字母的位置。如果信件是从nz,则二进制搜索它。然后,再次,只在您刚刚找到的内容之后搜索列表中的部分。

这值得保存两步吗?不知道。这很容易实现,但是再说一次,两个步骤不需要很长时间。 (正确地猜测这封信最多可以节省4步。)

另一种可能性是开始为每个字母设置垃圾箱。它开始已经排序,如果你必须重新排序,你只需要在一个字母内排序,而不是整个列表。缺点是如果你需要经常操作整个列表,你必须将所有的箱子粘在一起。