当我访问数组元素时,硬件级别会发生什么?

时间:2014-11-12 22:40:26

标签: c++ arrays hashtable

int arr [] = {69, 1, 12, 10, 20, 113};

当我这样做时会发生什么

int x = a[3];

????

我一直认为a[3]意味着:

" 从内存地址arr开始。 向前走3个内存地址。 获取在该内存地址处表示的整数。"

但后来我对哈希表的工作原理感到困惑。因为如果哈希表被实现为"桶的数组" (就像教授在这个讲座中说的那样:https://www.youtube.com/watch?v=UPo-M8bzRrc),那么你仍然需要走到你需要的水桶;因此,它们的访问效率不比阵列高。

有人可以为我清楚吗?

5 个答案:

答案 0 :(得分:4)

int x = a[3];

硬件确实(地址a)+(3 * sizeof(int))

这是标准的索引操作,通常可以通过专用硬件一步完成。

答案 1 :(得分:4)

想象一下内存是一个很大的两列表:

+---------+-------+
| ADDRESS | VALUE |
+---------+-------+
|     ... |   ... |
+---------+-------+
|     100 |    69 |  <-- &arr[0] is 100
+---------+-------+
|     101 |     1 |
+---------+-------+
|     102 |    12 |
+---------+-------+
|     103 |    10 |  <-- &arr[3] is 103
+---------+-------+
|     104 |    20 |
+---------+-------+
|     105 |   113 |
+---------+-------+
|     ... |   ... |
+---------+-------+

我想强调的是,这是一个高度简化模型,但它可以让您了解正在发生的事情。您的计算机知道您的阵列始于,让我们说地址100 。并且,由于给定数组中的所有元素大小相同,因此可以通过向起始地址添加+3来轻松访问数组的第三个元素。电脑不需要走路&#34;对于数组的第三个元素,它只是抓取存储在地址 100 + 3 的内存中的值。

如果您想查看此操作的示例,请编译并运行以下代码:

#include <iostream>
using namespace std;

int main() {
    int a[] = { 1, 2, 3 };
    cout << "Address of a:\t\t" << &a[0] << endl;
    cout << "Address of a[2]:\t" << &a[2] << endl;
    return 0;
}

记下 a 的地址。假设您的计算机使用32位整数,您应该看到 a [2] 的地址只是 a + 2 * 4 的地址。它增加2 * 4而不仅仅是2的原因是因为每个整数实际上使用4个字节的内存(即单个值将跨越4个地址)。

答案 2 :(得分:1)

如果你写这样的话:

int x = a[3];

然后编译器在编译时知道在哪里寻找变量,因此它可以在编译时设置相对和精确的内存位置。处理器不需要计算变量在内存中的位置。

  

“从内存地址arr开始。向前走3个内存地址。获取   在该内存地址处表示的整数。“

所以基本上,这是事实,但这只是为了教育目的而写的。 这不是处理器在这种情况下会做什么

通过哈希表访问元素时,将根据键计算哈希值。许多密钥可能导致相同的哈希值。因此,必须存在存储具有相同散列值的许多对象的位置,并且该位置称为 bucket 。因为存储桶中可以存在许多对象,所以必须搜索所需的值,但仍然比存储在数组中的所有值(您必须遍历其所有元素)更快的解决方案

答案 3 :(得分:0)

这基本上是阵列访问的工作原理,它非常快。散列表并不比数组快;事实上,这是因为它们与数组一样快,因此它们被认为非常快。哈希表的主要优点是您可以使用任何哈希类型作为键,而不仅仅是整数。此外,它们支持稀疏数据,而不会产生一堆浪费的数组空间。

答案 4 :(得分:0)

  

它们的访问效率不比数组高。

这并没有说太多,因为数组的速度非常快。索引数组(即,从一个对象转到该数组中的随机其他对象)是O(1) - 单个加法运算。大多数处理器甚至都有专门的指令,可以以各种形式索引到数组和子对象,甚至可以做得更好。

处理器不会遍历路上的每个地址 - 它会跳过它们,无论有多少地址。 “像阵列访问一样高效”确实受到高度赞扬。