- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的背景主要是 C++,现在我正在愤怒地编写一些 Java。我发现在 C++ 中使用 STL 的一些基本内容在 Java 中似乎比我认为的更麻烦。我的结论是,可能有一个更好的 Java 惯用语我还没有理解。这是一个使用伪代码的示例。
我有一些事物的集合,这些事物具有基于某些碰巧是字符串的成员变量的自然排序关系。
class Thing
{
String key1;
String key2;
}
在 C++ 中,我可能会定义一个排序运算符 <(Thing,Thing) 并将它们放在 std::set 中。例如
///
/// @brief
/// provide a total order for 'Things' using key1 and key2
///
bool operator<(const Thing& a, const Thing& b)
{
if (a.key1 < b.key1) return true;
else if (a.key1 > b.key1) return false;
else return a.key2 < b.key2;
}
然后我可以使用 set::find 在 O(log N) 时间内找到元素,以处理有事物的情况。使用 operator<() 的额外重载。我可以使用 std::lower_bound 或 std::equal_range 只搜索 key1 或同时搜索 key1 和 key2。例如:
struct Ordering
{
/// A strict weak ordering not a total ordering
bool operator()(const Thing& A,const std::string& key1) const;
}
const_iterator iter = std::lower_bound(someThings.begin(),
someThings.end(),
key1,
Ordering());
为了不那么抽象,假设 key1 是名称,key2 是版本。我可以问一下我们是否有任何名为 Foobar 的软件,或者更具体地说,我们是否有 Foobar v1.0。
从表面上看,Java 中 std::set 最直接的等价物似乎是 TreeSet可以通过子类化 Comparator 接口(interface)来实现排序。然而,对于我所说的,看起来需要多个 map 才能在 Java 中执行此操作。在 C++ 中,如果我想更改值,只会费心使用像 std::map 这样的关联容器。在 C++ std::set 中,就像在 Java TreeSet 中一样,值是它自己的键。但是,在 C++ 中,我可以编写比较器,根据需要使用 key1 或 key2 将“Thing”与“std::string”进行比较,并在它们的 std::set 中找到特定的事物。在我看来,您必须使用 Map 在 Java 中执行此操作。否则(因为 Comparator 只有一个类型参数)你最终会像这样一团糟:
public static class Order implements Comparator<Object>
{
@Override
@Constant
public int compare(Object a, Object b)
{
String aString;
String bString;
if (a instanceof String)
{
aString = (String)a;
}
else if (a instanceof Thing)
{
aString = ((Field)a).getKey1();
}
else
{
throw new ClassCastException("String or Field object expected.");
}
if (b instanceof String)
{
bString = (String)b;
}
else if (b instanceof Thing)
{
bString = ((Field)b).getKey1();
}
else
{
throw new ClassCastException("String or Field object expected.");
}
return aString.compareTo(bString);
}
};
但是,如果这样做,您可以(在 Thing 类中)写:
Set<Thing> things = new TreeSet<Thing>(new Order());
boolean hasFieldWithKey1(final String key1)
{
return this.fields.contains(key1);
}
使用 Java Set,您只能测试是否存在,而不能检索您正在搜索的对象。例如你做不到
Field getFieldWithKey1(final String key1)
{
return this.fields.floor(key1);
}
因为像 floor() 这样的方法只接受值类型的对象(即 Thing)
显而易见的解决方案是为每个键使用一个 Map。
Map<String,Thing> thingsByKey1 = new TreeMap<Thing>(new Order());
来自 C++ 背景,这似乎不必要地臃肿。当东西已经包含 key 时,为什么还要再次存储 key ?如果我有两把 key ,那就更糟了。我需要两张 map 。
Map<String,Thing> thingsByKey1 = new TreeMap<Thing>(new OrderByKey1());
Map<String,Thing> thingsByKey2 = new TreeMap<Thing>(new OrderByKey2());
我现在不仅要复制键,还要创建额外的不必要的树数据结构(或具有更好运行时性能的 HashMap)。对于上面的排序实现,这也可能是“完全错误的”,因为每个键本身仅形成部分顺序,而不是一组事物的总顺序。
我在此处看到有关使用线性搜索回答搜索的问题,这几乎总是最糟糕的选择。例如
Finding all objects that have a given property inside a collection
我注意到有一个 BinarySearch 版本接受 Comparator 对象作为参数,但返回元素的索引而不是元素本身。这意味着在使用它之后会不必要地调用 get()(假设集合支持它)。
那么 Java 在时间和空间上高效地执行此操作的方法是什么?
最佳答案
Java 的方法是,是的,使用 Map
.
Coming from a C++ background this seems unnecessarily bloated. Why should I store the key again when thing already contains it?
这并没有您想象的那么多。您正在存储一个对 String
的额外引用,总成本为...4 字节。 (实际上,成本为零:TreeSet
实现占用的内存与 TreeMap
一样多。)
如果您想同时使用两个键进行搜索,您可以使用 Comparator<Thing>
比较两个键,或使 Thing
实现 Comparable<Thing>
, 然后维护一个 TreeSet<Thing>
.这比......令人不快的Comparator
紧凑得多你在上面写了。如果要一键搜索,只需使用 Map<String, Thing>
.如果您真的非常想同时使用两者进行搜索,那么请同时维护它们。 (实际上,我几乎从来不需要这样做……而且 JDK 集合框架的作者也不认为您需要经常这样做。)
关于java - C++ 到 Java : searching a collection efficiently,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11765045/
我在一个数据集中有一个来自不同来源的姓名列表:一组按 FirstName LastName 组织;另一个有全名。我想查看名字或姓氏是否在全名列中,并创建一个标志。两个问题: 首先,我 u sed th
我一直认为不存在是正确的方法,而不是使用不存在条件。但是,我对我一直使用的查询进行比较,我注意到“Not In”条件的执行实际上似乎更快。任何关于为什么会出现这种情况的见解,或者如果到目前为止我只是做
我需要开发一个 iPad 应用程序,它应该管理两种方向模式(横向和纵向)。 根据 official Apple iOS documentation , 有 2 种方法可以继续。 -第一个包括在收到旋转
我有一个类有 2 个变量成员: class A: fullname = "" email = "" 内存中存储了一个A的列表,现在我需要针对全名或电子邮件进行搜索,搜索需要支持模糊搜索
哪个更有效率?或者它们都同样有效?带星号的行中的底层架构发生了什么? (1) for(int i = m_size; i > index; --i) { int k = normalize(
要检查两个不同日期范围的重叠,{Start1, End1} 和 {Start2, End2} 我正在检查: if ((Start1 = Start2)) { //overlap exists }
这个问题在这里已经有了答案: 关闭 13 年前. Possible Duplicate: Is there a performance difference between i++ and ++i i
前言: 学习ComfyUI是一场持久战, efficiency-nodes-comfyui是提高工作流创造效率的工具,包含效率节点整合工作流中的基础功能,比如Efficient Loader节点相当
我正在编写一个 Java 小程序,并且正在尝试读取一个 220K 行 (9.2 MB) 的文本文件,该文件是用 .jar 归档的。我相信我对文本文件的唯一合理访问是InputStream。为了使用 I
我有一个 Java 应用程序,需要播放一些不同的“声音/连复段”来指示状态。我想知道是否最好将这些记录为音频文件(wav 或任何格式)并使用 Java 音频类播放它们,或者存储 MIDI 数据并使用
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
很抱歉这个问题太基本了。 目标:这是我的软件程序的输出: 1 590 SC 1.000 LEU2_YEAST 100% 1 590 EC 1.000 LEU2_ECOLI 10
重复使用 $(this) 是否有效,还是将其保存到变量中更好?我已经看到它在很多 jQuery 代码中重复使用,但由于它是对构造函数的调用,我认为它应该不必要地慢,我错了吗? 最佳答案 只是为了好玩
我正在考虑编写一个函数,该函数使用 calloc 创建一个数组来容纳文件中的数据(目前以字符形式)。据我了解,我的两个最明显的选择是读取所有字符以获得所需的总大小,使用 calloc 分配所需的空间,
好的,假设我有如下类: public class KPIObject // Data { get; set; } public string Caption { get; set; } } p
我想对表演者数组进行排序,以便他们按名字的第一个字符进行分组。例如,以下输出中的“A”代表名字以“A”开头的表演者的集合。 [ "A"[Performer,Performer,Performer,Pe
我正在使用此 MySQL 语句来查找社区的平均特性评估。问题是我必须为每个邻域添加一条 SELECT 语句——而且有很多邻域。有没有办法不必指定“RIVER FRONT”或“OLD TOWN”?有没有
我有许多表,大约有四个,我希望连接在一起。为了使我的代码更清晰和可读(对我而言),我希望一次加入所有代码,然后在最后过滤: SELECT f1, f2, ..., fn FROM t1 INNER J
我有以下代码: setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); # statement handle (prevents in
我有一个巨大的数据文件,我只需要这个文件中的特定数据,以后我会经常使用这些数据。那么这两种方法中哪一种更有效: 将此数据保存在全局变量(可能是 LinkedList)中,并在每次需要时使用它们 将它们
我是一名优秀的程序员,十分优秀!