php数据结构大小堆 php 数组大小
数据结构:堆(Heap)
堆就是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
创新互联建站主要从事网页设计、PC网站建设(电脑版网站建设)、wap网站建设(手机版网站建设)、成都响应式网站建设公司、程序开发、网站优化、微网站、小程序设计等,凭借多年来在互联网的打拼,我们在互联网网站建设行业积累了丰富的成都网站制作、成都做网站、外贸营销网站建设、网站设计、网络营销经验,集策划、开发、设计、营销、管理等多方位专业化运作于一体。
堆的常用方法:
堆分为两种: 最大堆 和 最小堆 ,两者的差别在于节点的排序方式。
在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。
例子:
这是一个最大堆,,因为每一个父节点的值都比其子节点要大。 10 比 7 和 2 都大。 7 比 5 和 1 都大。
根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常有用,因为堆常常被当做优先队列使用,因为可以快速地访问到“最重要”的元素。
堆并不能取代二叉搜索树,它们之间有相似之处也有一些不同。我们来看一下两者的主要差别:
节点的顺序。 在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。
内存占用。 普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配内存。堆仅仅使用一个数据来存储数组,且不使用指针。
平衡。 二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到 O(log n) 。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足堆属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证 O(log n) 的性能。
搜索。 在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。
用数组来实现树相关的数据结构也许看起来有点古怪,但是它在时间和空间上都是很高效的。
我们准备将上面例子中的树这样存储:
就这么多!我们除了一个简单的数组以外,不需要任何额外的空间。
如果我们不允许使用指针,那么我们怎么知道哪一个节点是父节点,哪一个节点是它的子节点呢?问得好!节点在数组中的位置index 和它的父节点以及子节点的索引之间有一个映射关系。
如果 i 是节点的索引,那么下面的公式就给出了它的父节点和子节点在数组中的位置:
注意 right(i) 就是简单的 left(i) + 1 。左右节点总是处于相邻的位置。
我们将写公式放到前面的例子中验证一下。
复习一下,在最大堆中,父节点的值总是要大于(或者等于)其子节点的值。这意味下面的公式对数组中任意一个索引 i 都成立:
可以用上面的例子来验证一下这个堆属性。
如你所见,这些公式允许我们不使用指针就可以找到任何一个节点的父节点或者子节点。事情比简单的去掉指针要复杂,但这就是交易:我们节约了空间,但是要进行更多计算。幸好这些计算很快并且只需要 O(1) 的时间。
理解数组索引和节点位置之间的关系非常重要。这里有一个更大的堆,它有15个节点被分成了4层:
图片中的数字不是节点的值,而是存储这个节点的数组索引!这里是数组索引和树的层级之间的关系:
由上图可以看到,数组中父节点总是在子节点的前面。
注意这个方案与一些限制。你可以在普通二叉树中按照下面的方式组织数据,但是在堆中不可以:
在堆中,在当前层级所有的节点都已经填满之前不允许开是下一层的填充,所以堆总是有这样的形状:
小测验,假设我们有这样一个数组:
这是一个有效的堆吗?答案是 yes !一个从低到高有序排列的数组是以有效的最小堆,我们可以将这个堆画出来:
堆属性适用于每一个节点,因为父节点总是比它的字节点小。(你也可以验证一下:一个从高到低有序排列的数组是一个有效的最大堆)
如果你好奇,这里有更多的公式描述了堆的一些确定属性。你不需要知道这些,但它们有时会派上用场。 可以直接跳过此部分!
树的 高度 是指从树的根节点到最低的叶节点所需要的步数,或者更正式的定义:高度是指节点之间的边的最大值。一个高度为 h 的堆有 h+1 层。
下面这个对的高度是3,所以它有4层:
如果一个堆有 n 个节点,那么它的高度是 h = floor(log2(n)) 。这是因为我们总是要将这一层完全填满以后才会填充新的一层。上面的例子有 15 个节点,所以它的高度是 floor(log2(15)) = floor(3.91) = 3 。
如果最下面的一层已经填满,那么那一层包含 2^h 个节点。树中这一层以上所有的节点数目为 2^h - 1 。同样是上面这个例子,最下面的一层有8个节点,实际上就是 2^3 = 8 。前面的三层一共包含7的节点,即: 2^3 - 1 = 8 - 1 = 7 。
所以整个堆中的节点数目为:* 2^(h+1) - 1*。上面的例子中, 2^4 - 1 = 16 - 1 = 15
叶节点总是位于数组的 floor(n/2) 和 n-1 之间。
有两个原始操作用于保证插入或删除节点以后堆是一个有效的最大堆或者最小堆:
shiftUp 或者 shiftDown 是一个递归的过程,所以它的时间复杂度是 O(log n) 。
基于这两个原始操作还有一些其他的操作:
上面所有的操作的时间复杂度都是 O(log n) ,因为 shiftUp 和 shiftDown 都很费时。还有少数一些操作需要更多的时间:
堆还有一个 peek() 方法,不用删除节点就返回最大值(最大堆)或者最小值(最小堆)。时间复杂度 O(1) 。
我们通过一个插入例子来看看插入操作的细节。我们将数字 16 插入到这个堆中:
堆的数组是: [ 10, 7, 2, 5, 1 ] 。
第一股是将新的元素插入到数组的尾部。数组变成:
相应的树变成了:
16 被添加最后一行的第一个空位。
不行的是,现在堆属性不满足,因为 2 在 16 的上面,我们需要将大的数字在上面(这是一个最大堆)
为了恢复堆属性,我们需要交换 16 和 2 。
现在还没有完成,因为 10 也比 16 小。我们继续交换我们的插入元素和它的父节点,直到它的父节点比它大或者我们到达树的顶部。这就是所谓的 shift-up ,每一次插入操作后都需要进行。它将一个太大或者太小的数字“浮起”到树的顶部。
最后我们得到的堆:
现在每一个父节点都比它的子节点大。
我们将这个树中的 (10) 删除:
现在顶部有一个空的节点,怎么处理?
当插入节点的时候,我们将新的值返给数组的尾部。现在我们来做相反的事情:我们取出数组中的最后一个元素,将它放到树的顶部,然后再修复堆属性。
现在来看怎么 shift-down (1) 。为了保持最大堆的堆属性,我们需要树的顶部是最大的数据。现在有两个数字可用于交换 7 和 2 。我们选择这两者中的较大者称为最大值放在树的顶部,所以交换 7 和 1 ,现在树变成了:
继续堆化直到该节点没有任何子节点或者它比两个子节点都要大为止。对于我们的堆,我们只需要再有一次交换就恢复了堆属性:
绝大多数时候你需要删除的是堆的根节点,因为这就是堆的设计用途。
但是,删除任意节点也很有用。这是 remove() 的通用版本,它可能会使用到 shiftDown 和 shiftUp 。
我们还是用前面的例子,删除 (7) :
[图片上传失败...(image-d46ac4-1534077058042)]
对应的数组是
你知道,移除一个元素会破坏最大堆或者最小堆属性。我们需要将删除的元素和最后一个元素交换:
最后一个元素就是我们需要返回的元素;然后调用 removeLast() 来将它删除。 (1) 比它的子节点小,所以需要 shiftDown() 来修复。
然而,shift down 不是我们要处理的唯一情况。也有可能我们需要 shift up。考虑一下从下面的堆中删除 (5) 会发生什么:
现在 (5) 和 (8) 交换了。因为 (8) 比它的父节点大,我们需要 shiftUp() 。
php如何判断一堆数字大小
你这么问是要一个思路吧,我现在能想到两种方法
一丶先从大到小排成一个递减数组array1,然后定义array2,再按要求排序给array2,循环n次(n=array1.lengh),然后奇数位读array1的头部,偶数位读array1的尾部便是了
while(i=0,in,i++){
if(i%2==0) array2(i)=array1(i/2);
else array2(i)=array1(n-(i+1)/2);
}
二、用递归,写两个函数,函数A结尾调用函数B,函数B结尾调用函数A。A用来将array1中最大数赋给array2后删除array1的这个数,B则相反。同样用n来控制程序。
建议方法1,毕竟递归这种算法太消耗的计算机资源
数据结构中堆的定义是???
堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
堆总是满足下列性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值;
2、堆总是一棵完全二叉树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。堆是非线性数据结构,相当于一维数组,有两个直接后继。
扩展资料:
操作实现
在程序中,堆用于动态分配和释放程序所使用的对象。在以下情况中调用堆操作:
1、事先不知道程序所需对象的数量和大小。
2、对象太大,不适合使用堆栈分配器。
堆使用运行期间分配给代码和堆栈以外的部分内存。
传统上,操作系统和运行时库随附了堆实现。当进程开始时,操作系统创建称为进程堆的默认堆。如果没有使用其他堆,则使用进程堆分配块。语言运行时库也可在一个进程内创建单独的堆。
当应用程序或 DLL 创建专用堆时,这些堆驻留于进程空间中并且在进程范围内是可访问的。某一给定堆分配的任何数据应为同一堆所释放。(从一个堆分配并释放给另一个堆没有意义。)
参考资料来源:百度百科-堆
【数据结构】堆(优先队列):二叉堆、d堆、左式堆、斜堆与二项队列
这是数据结构类重新复习笔记的第 五 篇,同专题的其他文章可以移步:
堆 (Heap)又称为 优先队列 (priority queue),在队列的基础上,堆允许所有队列中的元素不一定按照 先进先出 (FIFO)的规则进行,而是使得每个元素有一定的优先级,优先级高的先出队列。
优先队列至少存在两个重要的操作:
有几种简单而明显的方法实现优先队列。
二叉堆 (binary heap)是一种对于优先队列的实现,可以简称为堆
堆是一棵 完全二叉树 (complete binary tree),即所有节点都必须有左右两个子节点,除了最后一排元素从左向右填入,直到没有元素为止。
很显然,一棵高为h的完全二叉树有 2^h 到 2^(h+1)-1 个节点,即其高度为 logN 向下取整。
完全二叉树的好处在于其规律性,可以使用一个数组而不需要链表来表示
对于数组中任一位置 i 上的元素,其左儿子在位置 2i 上,右儿子在左儿子后的单元 (2i+1) 上,它的父亲则在位置 i/2 向下取整上。
因此,不仅不需要链,而且遍历该树所需要的操作也极简单,在大部分计算机上都可能运行得非常快。唯一问题是最大的堆的大小需要事先估计。
使操作可以快速执行的性质是 堆序性质 (heap-order property):对于每一个节点X,X的父节点中的键小于等于X中的键,除没有父节点根节点外。
将待插入的元素首先放置在最后一个位置上,以保证他是一个完全二叉树,然后将该元素与其父节点(i/2向下取整)比较,如果比其父节点小,就将两者互换,互换后再和新的父节点比较,这种方式称为 上滤 (percolate up),得到一个小顶堆(min heap),如果比较的时候是较大的值向上走,就会得到一个大顶堆(max heap)
比如向一个小顶堆中插入元素14的操作:
找出、返回并删除最小元非常简单,最小元就是根节点处的元素,将其返回并删除。接下来是处理这个B。首先拿下最后一个元素X,如果元素X比B的两个子节点都小,可以直接将X插入到B的位置,如果X比B的两个子节点中的任意一个大,就不能插入,此时找到两个子节点中较小的那个放到B处,B转而移至这个子结点处。重复如上的步骤直到X可以插入B处为止。这个操作成为 下滤 (percolate down)
比如从一个小顶堆中删除根节点
decreaseKey(p, A) 操作减小在位置p处的元素的值,减少量为A,可以理解为调高了某个元素的优先级。操作破坏了堆的性质,从而需要上滤操作进行堆的调整。
increaseKey(p, A) 操作增加在位置p处的元素的值,增加量为A,可以理解为降低了某个元素的优先级。操作破坏了堆的性质,从而需要下滤操作进行堆的调整。
remove(p) 操作删除在堆中位置p处的节点,这种操作可以通过连续执行 decreaseKey(p, ∞) 和 deleteMin() 完成,可以理解马上删除某个一般优先级的元素
即将一个原始集合构建成二叉堆,这个构造过程即进行N次连续的 insert 操作完成
定理 :包含 2^(h+1)-1 个节点且高度为h的理想二叉树(perfect binary tree)的节点的高度和为 2^(h+1)-1-(h+1)
d堆 (d-Heaps)是二叉堆的简单推广,它与二叉堆很像,但是每个节点都有d个子节点,所以二叉堆是d为2的d堆。d堆是完全d叉树。比如下边的一个3堆。
d堆比二叉堆浅很多,其insert的运行时间改进到 O(logdN) 。但是deleteMin操作比较费时,因为要在d个子节点中找到最小的一个,需要进行d-1次比较。d堆无法进行find操作,而且将两个堆合二为一是很困难的事情,这个附加操作为merge合并。
注意! 在寻找节点的父节点、子节点的时候,乘法和除法都有因子d。如果d是一个2的幂,则可以通过使用二进制的 移位 操作计算,这在计算机中是非常省时间的。但是如果d不是一个2的幂,则使用一般的乘除法计算,时间开销会急剧增加。有证据显示,实践中,堆可以胜过二叉堆
这些高级的数据结构很难使用一个数据结构来实现,所以一般都要用到链式数据结构,这种结构可能会使得其操作变慢。
零路径长 (null path length)npl(X):定义为从一个X节点到其不具有两个子节点的子节点的最短路径长,即具有0个或者1个子节点的节点npl=0,npl(null)=-1,任意节点的零路径长都比其各个子节点中零路径长最小值多1。
左式堆 (leftist heap)是指对于任意一个节点X,其左子节点的零路径长都大于等于其右子节点的零路径长。很显然,左式堆趋向于加深左路径。比如下边的两个堆,只有左边的是左式堆,堆的节点标示的是该节点的零路径长。
左式堆的实现中,需要有四个值:数据、左指针、右指针和零路径长。
定理 :在右路径上有r个节点的左式堆必然至少有 2^r-1 个节点
merge 是左式堆的基本操作, insert 插入可以看成是一个单节点的堆与一个大堆的 merge , deleteMin 删除最小值操作可以看成是首先返回、删除根节点,然后将根节点的左右子树进行 merge 。所以 merge 是左式堆的基本操作。
假设现在有两个非空的左式堆H1和H2,merge操作递归地进行如下的步骤:
例如如下的两个堆:
将H2与H1的右子树(8--17--26)进行merge操作,此时(8--17--26)和H2的merge操作中又需要(8--17--26)和H2的右子堆(7--37--18)进行merge操作……如此递归得到如下的堆:
然后根据递归的最外层(回到H1和H2的merge的第二步),将上边合并的堆成为H1的右子堆
此时根节点(3)处出现了左右子堆不符合左式堆的情况,互换左右子堆并更新零路径长的值
斜堆 (skew heap)是左式堆的自调节形式,实现起来极其简单。斜堆和左式堆的关系类似于伸展树和AVL树之间的关系。斜堆是具有堆序的二叉树,但是不存在对树的结构的现限制。不同于左式堆,关于任意结点的零路径长的任何信息都不保留。斜堆的右路径在任何时刻都可以任意长,因此,所有操作的最坏情形运行时间均为O(N)。然而,正如伸展树一样,可以证明对任意M次连续操作,总的最坏情形运行时间是 O(MlogN)。因此,斜堆每次操作的 摊还开销 (amortized cost)为O(logN)
斜堆的基本操作也是merge合并,和左式堆的合并相同,但是不需要对不满足左右子堆的左式堆条件的节点进行左右子堆的交换。斜堆的交换是无条件的,除右路径上所有节点的最大者不交换它的左右儿子外,都要进行这种交换。
比如将上述的H1和H2进行merge合并操作
首先进行第一步,除了交换左右子树的操作与左式堆不同,其他的操作都相同
将合并的堆作为H1的右子堆并交换左右子堆,得到合并后的斜堆
二项队列 (binomial queue)支持merge、insert和deleteMin三种操作,并且每次操作的最坏情形运行时间为O(logN),插入操作平均花费常数时间。
二项队列不是一棵堆序的树,而是堆序的树的集合,成为 森林 (forest)。堆序树中的每一棵都是有约束的 二项树 (binomial tree)。二项树是每一个高度上至多存在一棵二项树。高度为0的二项树是一棵单节点树,高度为k的二项树Bk通过将一棵二项树Bk-1附接到另一棵二项树Bk-1的根上而构成的。如下图的二项树B0、B1、B2、B3和B4。
可以看到二项树Bk由一个带有儿子B0,B1,……,Bk-1的根组成。高度为k的二项树恰好有2^k个节点,而在深度d处的节点数为二项系数Cdk。
我们可以使用二项树的集合唯一地表示任意大小的优先队列。以大小为13的队列为例,13的二进制表示为1101,从而我们可以使用二项树森林B3、B2、B0表示,即二进制表示的数中,第k位为1表示Bk树出现,第k位为0表示Bk树不出现。比如上述的堆H1和堆H2可以表示为如下的两个二项队列:
二项队列额merge合并操作非常简单,以上边的二项队列H1、H2为例。需要将其合并成一个大小为13的队列,即B3、B2、B0。
首先H2中有一个B0,H1中没有,所以H2中的B0可以直接作为新的队列的B0的树
其次H1和H2中两个B1的树可以合并成一个新的B2的树,只需要将其中根节点较小的堆挂到根节点较大的堆的根节点上。这样就得到了三棵B2堆,将其中根节点最大的堆直接放到新队列中成为它的B2堆。
最后将两个B2堆合并成一个新队列中的B3堆。
二项队列的deleteMin很简单,只需要比较队列中所有二项堆的根节点,返回和删除最小的值即可,时间复杂度为O(logN),然后进行一次merge操作,也可以使用一个单独的空间每次记录最小值,这样就可以以O(1)的时间返回。
森林中树的实现采用“左子右兄弟”的表示方法,然后二项队列可以使用一个数组来记录森林中每个树的根节点。
例如上边的合成的二项队列可以表示成如下的样子:
STL中,二叉堆是通过 priority_queue 模板类实现的,在头文件 queue 中,STL实现一个大顶堆而不是小顶堆,其关键的成员函数如下:
PHP优先队列、二叉堆、大顶堆、小顶堆
先进后出(FILO),就像一个敞口向上的容器,只能将后进入容器的先弹出。
先进先出(FIFO),跟栈相反,队列就像一根上下贯通的水管,只能将先流入水管的水流出去。
优先队列也是一种数据结构,通过加权值进行排序,PHP核心库提供了 SplPriorityQueue 对象来实现。
优先队列内部是用 Heap:堆 这种数据结构来实现的,默认是大顶堆(MaxHeap)。
优先队列改成小顶堆,需要重写compare方法,将比较值对调,即可切换小顶堆和大顶堆。
堆就是为了实现优先队列而设计的一种数据结构,它分为大顶堆和小顶堆,PHP核心库提供了 大顶堆SplMaxHeap 和 小顶堆SplMinHeap 两种类可供直接使用,他们都是由SplHeap抽象类实现的。
总结:
急!!!数据结构中什么是堆?清举例说明。
堆栈
在计算机领域,堆栈是一个不容忽视的概念,但是很多人甚至是计算机专业的人也没有明确堆栈其实是两种数据结构。
要点:
堆:顺序随意
栈:先进后出
堆和栈的区别
一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活
2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
2.6存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。
?
2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
堆和栈的区别主要分:
操作系统方面的堆和栈,如上面说的那些,不多说了。
还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。
虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。
名称栏目:php数据结构大小堆 php 数组大小
URL链接:http://pwwzsj.com/article/hijdid.html