【问题标题】:Arduino Hash Table/DictionaryArduino哈希表/字典
【发布时间】:2013-03-21 14:30:59
【问题描述】:

我正在尝试让哈希表或字典在 Arduino Mega 2560 上工作。我的目标是拥有类似的东西

dictionary[ENGLISH]["ACCOUNT"] = "Account";
dictionary[ENGLISH]["DATE_AND_TIME"] = "Date and Time";
dictionary[ENGLISH]["IDLE"] = "Idle";
dictionary[ENGLISH]["Language"] = "Languge"
dictionary[ENGLISH]["MAIN_MENU"] = "Main Menu";
dictionary[ENGLISH]["PRESCRIPTION"] = "Prescription";
dictionary[ENGLISH]["SETTINGS"] = "Settings";
dictionary[ENGLISH]["SOUND"] = "Sound";

其中 ENGLISH 本质上是一个常数 0,我也会有 SPANISH 和 FRENCH(分别为 1 和 2)。也就是说,一个由 3 个字典元素组成的数组。

在第一次 Google 搜索中,我找到了一个模拟 C++ STL 的库的 link,但它根本不适用于我的 Arduino 1.0.3。我想知道是否有人可以为我在 arduino 中使用地图/哈希表的替代方法,修复以使提到的库正常工作。

对于我的情况,我正在通过 Arduino 上的触摸屏对菜单系统进行建模,它必须接受 3 种语言(用于按钮)。所选语言位于 EEPROM 中的某个位置,我会将其保存在变量 'lang' 中,当我需要在屏幕上打印某些内容时,我会执行以下操作:

    screen.print(dictionary[lang]["SOUND"], CENTER, 23);

根据用户选择的“语言”,理想情况下,它会相应地打印。

【问题讨论】:

  • std::map<int, std::map<std::string, std::string> > 怎么样?
  • 据我所知,目前还没有 Arduino 的标准库,我上面提到的那个对我不起作用(我理解你的建议:而不是制作一系列字典,制作一个字典,其中“lang”是字典中的第一个元素,但我现在没有办法使用地图。)(我澄清了我的问题!)
  • 每种语言有多少个条目?
  • @user529758 Arduino 没有标准库实现。 std 命名空间中不存在任何内容。

标签: hashmap arduino hashtable


【解决方案1】:

我认为这里可能不需要哈希表,无论如何在这个平台上都有充分的理由避免它。

为什么不需要哈希表

在这种情况下,通常不需要 string 键,因为该键仅在您的代码内部可见,并且不会与您的程序外部进行交互。因此,通常的解决方案是使用#define 形式的(伪)整数键,由预处理器而不是您的程序处理:

#define kWORDIDX_LANGUAGE   1
#define kWORDIDX_SOUND      2
#define kWORDIDX_MAINMENU   3
#define kWORDIDX_SPAGHETTI  4
...
dictionary[ENGLISH][kWORDIDX_SOUND] = "Sound";
...

然后您可以访问您的字典条目,例如 Sreen.print(dictionary[lang][kWORDIDX_SOUND], CENTER, 23); 或类似内容。

这种方法的优点是:

  • 您正在节省内存空间:没有使用字符串键
  • 您正在节省处理时间:虽然哈希表访问在技术上是 O(1),但仍然涉及到计算哈希的常量因素。数组访问速度更快。
  • 您的代码不太容易出错:如果您使用字符串访问(无论如何都是幻数的一种形式)拼错了您的密钥,您将得到一个哈希表未命中。如果你拼错了#defined 键之一,你会得到一个编译错误,这就是你想要的

为什么你不想在 Arduino 上使用哈希表

Arduino 是一个内存受限的平台:它的内存非常有限。使用真正的hash map的问题如下:

  • 字符串占用比ints(通常)更多的内存空间。使用 #define 键(编译器将其转换为整数文字),每个键使用 1、2 或 4 个字节(取决于您的编译器设置),而每个字符串键需要 strlen(s) + 1 存储空间。这个空间实际上被使用了两次:一次在闪存中(即变量初始化的地方),一次在 SRAM 中。
  • 哈希映射数据结构本身占用更多内存:哈希映射中的空条目(在open addressing 方案中)或链表(在separate chaining scheme 中)存在开销。由于您的数据是只读的,因此您不需要该开销,因为不会添加哈希表。
  • 人们用来在 Arduinos 中节省内存的一个技巧是使用 PROGMEM 关键字将只读数据(如字符串)仅存储在 program memory(而不是 SRAM)中。如果您使用哈希映射构建字典,则您将无法使用此路由。另一方面,给定上述#define-type 索引方案,将所有语言字符串存储为PROGMEM 字符串将非常容易。

【讨论】:

  • 写得真好!您能否更详细地了解我如何将 PROGMEM 用于您上面概述的方法?我以前用它来在屏幕上绘制时存储精灵,但没有这样的。谢谢!
  • 最好看一下“字符串数组”部分here:它有一个完整的PROGMEMPROGMEM 字符串示例。只是你会使用strcpy_P(buffer, (char*)pgm_read_word(&(string_table[kMY_DEFINED_INDEX])));(或类似的)而不是strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));(或类似的)。如果这没有帮助,可以在这里发布另一个问题:它似乎是一个不同的话题。你怎么看?
  • 太棒了!很高兴听到它。
  • 以及为什么我想要一个哈希表:如果数据被传递到 Arduino 并且您需要以灵活的方式解析并将其存储在 Arduino 上,某种字符串-字符串-字典(=哈希图)将非常适合这项工作。虽然我通常非常同意您的说法,但请记住,您将无法避免各种用例。
【解决方案2】:

您也可以使用数据结构来定义字典:

typedef struct { 
  uint8_t lang;
  char* sound;
  char* value;
} langDictionary;

然后你可以用要使用的值定义一个结构数组:

const langDictionary myDictionaryArr[] {
    {0, "ENGLISH", "Settings"},
    {1, "SPANISH", "Ajustes"},
    {2, "FRENCH", "Paramètres"}
};

最后你可以使用数组来搜索属性:

void setup() {
  Serial.begin(115200);
  for(uint8_t i = 0; i < sizeof(myDictionaryArr)/sizeof(langDictionary); ++i) {
      Serial.println(myDictionaryArr[i].value); //Prints the values: "Settings", "Ajustes" and "Paramètres"
  }
}

【讨论】:

  • 这是一个很好的技巧,当你想模拟字典时,键是数组的索引。
【解决方案3】:

虽然我完全同意前面的答案,但 arduino playground 的名称为“HashMap Library for Arduino”。

【讨论】:

  • 使用 HashMap 库会出现错误 missingWProgram.h missing。
  • @Ciastopiekarz,这与一般使用库无关 - 请在您的代码中包含提到的文件。
  • 好的,请尝试删除include 语句或将文件名更改为Arduino.h
  • 操场上有一个注释:提示:这不是一个真正的 hashmap,它是一个 key-value-map。在这个“HashMap”中搜索是通过对所有条目的简单迭代完成的,而不是通过散列键。在 O(N) 中执行查找、完全扫描数据的“哈希图”不是哈希图,而是糖衣数组
  • 我发现你不能重载这个Arduino hashmap来使用自定义结构,它只存储整数:(
猜你喜欢
  • 2012-08-23
  • 2014-01-04
  • 1970-01-01
  • 2010-10-18
  • 2013-01-15
  • 2011-06-10
  • 2017-07-18
  • 1970-01-01
  • 2016-03-31
相关资源
最近更新 更多