堆与栈 堆区和栈区的区别

一、 栈和堆事数据结构中的叫法,栈区和堆区是进程的内存模型中的堆区和栈区

二  内存模型里堆区和栈区和数据结构没有关系,底层也不是讲用了数据结构里边的堆栈存储方式。但是类似,堆区有编译器自动分配释放,存放函数的参数,局部变量等值,器操作那个方式类似于数据结构中的栈。堆区是一般有程序猿分配释放,若程序猿不分配释放,程序结束时候,可能有os回收,注意它于数据结构中堆是两码事情,分配方式类似链表。

下边详细的讲解  栈 堆 栈区和堆区的区别。

1 、栈是具有先进后出的性质的数据结构。

2、堆: 是一种经过排序的树形数据结构,节点的值最大或者最小,切根节点的两个子树也是一个堆,一般只二叉堆,常用用来实现优先队列。

3、栈和堆的大小,栈的大小在进程分配时确定的,具体大小看编译器。操作系统。所需大小一般小于10M,太大也没有意义,不符合栈的快速存取目标。 堆是动态分配的。堆的数据结构相对比较慢。因为会手动进行分配。会大一些。是自底向上分配的。从低地址到高地址分配的,大小不固定。于栈相反。

扩充:至于堆和栈那个更快?

(1)分配和释放,堆在分配和释放时候都需要调整函数(MALLoc,FREE),比如会分配时会到堆空间去需要足够大的空间(因为多次分配释放后会造成空洞)这些都会会飞一定的时间,具体可以看MALLOC和free的源码,他么你做了很多额外的工作,而且栈不需要这些,由于栈先进后出的特性和存储非常快,世纪上叶不是什么分配。知识从栈顶向上就行了,例如工程中的传送带,stackPointer 会自指引你到放东西的位置,你所要做的知识吧东西放下来就行,推出函数时候,修改栈指针就可以吧栈中的内容晓辉,这样的模式比较快。

扩充:stackPointer 堆栈指针?

如果的堆栈的实现是往上长的(就是说往顶的方向长,其实质是栈底是定死的不能动,入栈的东西只能不断往上叠,这就像在书桌上放书一样,桌底是定死的,所以书只能一本一本地往上堆,往上长),计算机内部的堆栈的实现采取的就是这种模式,所以就得“先修改指针,然后插入数 据,出栈时刚好相反”,因为堆栈指针指向的总是栈顶元素,栈底不能动,所以数据入栈前要先修改指针使它指向新的空余空间然后再把数据存进去,出栈的时候 自然相反,可以联系上面举的放书的例子。

      然而,如果堆栈的实现是往下长的(就是说每压一个元素入栈,栈底就自动下移一个元素的位置,其实质就是这种堆栈模型是一个“无底洞”型), 这个时候,栈顶就变成了定死的,就可以先压入元素,然后再修改指针。因为栈底是无限的,压入一个元素,新的元素就取代先前的栈顶元素占据栈顶 的位置,那么先前的指向栈顶元素的指针这个时候就该修改让它指向这个新的栈顶元素了。

接着来谁快的问题 (2)访问时间,访问对的一个具体但愿,需要两次访问内存,第一次取得指针,第二次才是真正得倒数据,而栈只需要访问一次,另外,堆的聂荣被操作系统交换到外存的概率比栈大,栈一般是不会被叫唤出去的。

3、数据结构里边的堆 

(1)感觉堆hi啊会死一个挺神秘的数据结构,优先队列,体现在一般只有个操作,掺入和出对最小值,也有最大堆。

(2)实现这两种操作的方法有,链表和排序链表和不排序链表的遍历。

扩充: 二叉树:最常用的,堆基本叫做二叉堆。

二叉堆事一个完全的二叉树,只有最下边一层不是满二叉树,且游戏安排在左侧。2^n到^(n+1) -1 的节点,时间复杂度为log(n)

性质1 我们想最快的找到min 则最小值应该在根节点,任意子树也是堆,所以任意父节点小于其子节点,

性质2 插入时候,第一步插入紧接着事左侧的根节点,不满足性质1 则和父节点交换,直至满足。称为 上滤

性质3 findmin 找到最小值简单 删除比较麻烦,沙鸥线根节点和删除后会有一个空穴,我么你定位到二叉树最后一个节点,在最后一个节点所在的分支里 ,一个一个  下滤  最小值上移 最后将最后一个节点 填入下滤 后的子节点留下的空穴


4 堆的应用 在对于数据,我们先建立一个最大或者最小的堆,时间为n 

对于数据,我们先建立一个最大(小)堆,时间为n(就是insert的平均时间,业内证明最坏是log(n),平均是1.607次即o(1),进行n次即为o(n)),然后进行n次 的删除。不过在删除前,我们新建一个数组,将最大值依次插进去。最后返回次数组,就是最大顺序排好的序列。n个元素总的删除时间为n*log(n)。则总的时间复杂度n+n*log(n),即nlog(n)。

      堆排序需要附加数组,存储增加一倍!好的方法是将刚刚删除的最大值,放到最后一个元素的位置上,最后会输出一个按最小值排序的数组,无需分配额外空间!(二叉树可以顺序也可以链式,完全二叉树用顺序的数组存储是最好的。

三 堆区和栈区的介绍

1、栈区。

       因为栈主要是为一个线程配备(栈是线程独享的)为这个线程的函数调用服务的。用于存放返回地址,参数,临时变量而用,记录多层调用,是一个有明确的“后入先出”规则的内存 buffer。而且是供程序员“隐式”的使用,分配和回收都是“自动”的,程序员对栈内存的使用缺少自由和可控性,栈这部分内存由专用的寄存器和指令来负责维护。其特点是栈的“复用率”很高,是连续的,且有 IN - OUT 次序的(对 ESP 的维护非常严格严谨,这个工作是编译器来负责,通常也不需要程序员去干预。计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。

      栈上对象的特点是尺寸小而且生命周期很短,潜规则是不要创建尺寸极大的临时对象,调用深度也不希望过深。所以如果栈太大,则对内存使用的性价比会降低(栈的顶部方向的那部分属于栈所有但位于栈外的那部分内存是几乎不会被使用到的,距离栈顶越远的栈外内存的被使用的概率越低,距离栈底越近的内存则使用率越高,热点集中在靠近栈底的部分,而远端方向则是空白的,就好像地铁车厢的高度,不会因为一个姚明这样的存在就把它设计的很高,那样就属于浪费),而且也会减少可以同时创建的进程的数量。

      栈只能进行push和pop两种操作,无论是排序,寻址,还是修改,删除,插入都很难,时间代价太高了。所以其实不是不能将栈变得很大,而是因为一旦变得很大,它在这个场景下就不是一个合理的数据结构了,应该选择其他的数据结构来解决。

由编译器自动分配释放,存放函数的参数值,局部变量值等,操作类似于数据结构中的栈。只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出,一般 Linux 为 8MB(ulimit -a 查看)。

2、堆区。

       而堆内存的使用特点是不连续和无序的,分配和释放成本较高堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。 一般由程序员/用户程序通过 malloc 或 free 等分配释放,若程序员/用户程序不主动释放,程序结束时可能由操作系统回收,分配和维护方式类似于链表。

操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

3、因此,栈和堆的设计体现了“分工”原则。栈的主要作用的为函数调用服务,并承担了生命周期很短和(编译器)“自动”维护,尺寸很小的临时对象的存储责任。堆则负责存储生命周期由程序员自主维护,以及尺寸极大的(例如明显超过栈的尺寸)对象/数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容