数组,矢量&链接列表

时间:2013-04-23 16:37:30

标签: c++ arrays data-structures vector linked-list

我的主要问题是矢量如何运作。

据我所知,链表是连接在一起的节点列表。这就是我在脑海中想象的方式。但我无法想象矢量是什么样的。

我读到矢量具有随机访问权限,就像数组一样。但什么是随机访问?计算机最终是否最终在内部搜索索引?我这样说是因为我可以通过运行for循环来重载[]运算符以在链表中给出i th 元素。

又是什么阵列?我知道数组是如何工作的,但它背后的是什么,它是一个节点集合吗?我只是为了一般知识而问这个。

Here是关于向量的问题。它看起来与用于链表的函数非常相似。

5 个答案:

答案 0 :(得分:6)

C ++中的vector是一个实际包装数组的类,并在向其添加新元素时自动调整数组大小。

数组本质上只是一个连续的内存块,其中每个元素都在内存中一个接一个地放置。

随机访问基本上意味着通过索引访问元素,即获取列表中的第5个元素。数组(以及vector)提供有效的随机访问,并对元素进行恒定时间查找。这意味着访问第5个元素和第573个元素一样快。

由于vector包装数组并将其数据作为数组存储在内部,因此元素查找的效率与数组(基本上)相同。并且它不需要查找索引或类似的东西,因为它将数据保存在数组中。

答案 1 :(得分:4)

通常,矢量有三个数据成员:

  • 指向数据开头的指针
  • 指向数据末尾的指针(或包含向量大小的整数)
  • 包含向量当前容量的整数(不用担心这个)

“数据”是一个数组,所以最终一个向量看起来像一个带有一些额外信息的数组的指针。

数组是内存中相邻对象的序列,因此每个对象都从比前一个对象的最后一个字节高一个字节的地址开始。

  

计算机最终是否最终搜索索引   内部?

不,RAM硬件的部分功能是在不扫描内存的情况下获取指定地址的内容。这就是RAM与(例如)旋转鼓存储器的区别。

在此上下文中,“随机访问”意味着最多在固定的时间内访问任何地址。

对于向量和数组,可以通过向第一个元素的地址添加偏移量来计算i元素的地址。以字节为单位的偏移量等于单个元素大小的i倍。使用链表,获取i元素的唯一方法是遵循next指针i次。因此,如果您为链接列表实现了operator[],则执行i的值越大需要更长时间,因此不会提供随机访问权限。

答案 2 :(得分:2)

向量(至少在C ++中)表示保持相同大小的对象的连续内存块。这允许它在恒定时间内计算任何给定项目的地址,例如:

address = base_address + index * item_size;

请注意,大部分内容都在幕后(可以这么说) - C ++(就像之前的C一样)根据计算某些指定大小的对象的地址来定义索引,所以实际上代码可能只是看起来像:

T &operator[](size_t index) { return base[index]; }

...并且编译器处理生成代码以基于sizeof(T)进行乘法。

这意味着访问数组的任何部分在代码方面需要基本相同的机制。公平地说,并不意味着所有访问都必须具有相同的速度。

例如,部分数据可能位于缓存中,其他部分位于主内存中,而其他部分可能位于虚拟内存中,其中检索需要从磁盘驱动器读取数据。这可能很容易意味着一百万比一(或更多)的速度差异。

然而,这仍然是与链表的对比,链表需要线性复杂度才能找到列表中任意项的地址。从那里开始,就数据的存储方式而言,我们得到了所有相同的可能性(由于数据不连续,我们往往会得到较差的参考局部,导致任何给定数据的可能性更大。一种较慢的存储形式。)

答案 3 :(得分:1)

不一定是某种语言,这些术语通常意味着:

  • 数组是连续内存的固定长度,非结构化区域。通过计算基址的偏移量来访问位置。
  • 矢量是一个像数组一样的随机访问,但知道它的长度,因此可以动态地改变它。
  • 链接列表完全是动态且非连续的,因此它不是随机访问。

答案 4 :(得分:1)

数组是内存中的一个位置,后面是一系列串行位置。

考虑我是否有数组int[] a = [1,2,3,4,5,6,7,8,9,10];

如果我们在内存中查看此数组,它可能看起来像这样 -

15  null           00000000
    null           00000000
    null           00000000
    a[10]          00001011
    a[9]           00001010
10  a[8]           00001001
    a[7]           00001000
    a[6]           00000111
    a[5]           00000110
    a[4]           00000101
5   a[3]           00000100
    a[2]           00000011
    a[1]           00000010
    a[0]           00000001
    other stuff    00011101
0   other stuff    01010101

您可以在数组中进行随机访问,因为编译器正在为您找到您正在寻找的确切地址。

例如,在这种情况下,如果我运行函数

print(a*); //print the location in memory of a (the pointer to a)

将输出

2

现在我要求[2]

print (a[2]) 

编译器实际做的是这个

print (&(a*+2) // print the values at the memory location 
               // that is 2 plus the pointer to a

这意味着它应该打印出内存位置4的值,即

3

当我们说数组具有随机访问权时,这意味着访问时间是恒定的,因为找到元素a [100000]和[1]都花费相同的时间。

1.) look-up a.
2.) add the index to a. 
3.) look-up the value at a + index. 

现在,矢量只是数组的包装器。它添加了特殊功能并为数组定义了“行为”。想象它就像一个包含3-4个数据的结构,其中一些数据是指向特殊“向量函数”的指针。

想象一下像这样的数据。

struct vect { 
    int* array; 
    int  arraysize; 
    int* functionPtr1;
    int* functionPtr2;
    int* functi....
};

我要避免看起来如何看待c,因为我不是很好并且肯定会出错。但是在像java这样的面向对象语言中,我们的向量看起来像这样

vect.array[1];
int arg2 = vect.array[2]; 
vect.functionPtr1(2); 
int vectSize = vect.arraysize; 

非常简单。令人困惑的是,c ++允许您在对象上定义[]运算符。在执行此操作时,在c ++中的向量中。

vect[2]; 

这实际上只是java等价的语法糖:

vect.array[2]; 

但是tl; dr;这一切的版本是一个向量只是一个用于包围原始数组周围的函数的对象。 C ++提供了特殊的synatic糖,因此您可以直接从对象指针处理原始数组,而不仅仅是来自对象数组成员,但是获取对象数组成员的工作仍在进行中,只是抽象掉了。

相关问题