堆和栈相关知识

来源:互联网 发布:vb 线程钩子 编辑:程序博客网 时间:2024/05/16 04:03

网上关于堆和栈的资源很多,推荐几篇文章

http://blog.csdn.net/hairetz/article/details/4141043 (堆和栈的区别,以及程序数据存储位置。非常好的文章)

http://jingyan.baidu.com/article/6c67b1d6a09f9a2786bb1e4a.html

http://www.cnblogs.com/jztan/p/5878630.html (常见的排序介绍、思想,还有动画演示)


摘取一点有用的信息:

 一、预备知识程序的内存分配  
  一个由C/C++编译的程序占用的内存分为以下几个部分  
  1、栈区(stack)——   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。  
  2、堆区(heap)   ——   一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。  
  3、全局区(静态区)(static)——  全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。   -   程序结束后由系统释放。  
  4、文字常量区   ——  常量字符串就是放在这里的。   程序结束后由系统释放  
  5、程序代码区  ——  存放函数体的二进制代码。  

二、例子程序

int a = 0;                      //全局初始化区char *p1;                       //全局未初始化区int main(){    int b;                      //栈    char s[] = "abc";           //栈    char *p2;                   //栈    char *p3 = "123456";        //123456/0在常量区,p3在栈上    static int c = 0;           //全局(静态)初始化区    p1 = (char *)malloc(10);    //分配得来得10和20字节的区域就在堆区    p2 = (char *)malloc(20);    strcpy(p1,"123456");        //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方}

三、堆、栈区别总结:

1.堆栈空间分配
 ①栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
 ②堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
2.堆栈缓存方式
①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
3.堆栈数据结构区别
①堆(数据结构):堆可以被看成是一棵树,如:堆排序。
②栈(数据结构):一种先进后出的数据结构。


四、顺带复习堆排序

介绍:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

大根堆排序基本思想:

① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。(对照着最后一个参考文章看看)

实现代码:

#include<iostream>using namespace std;//arr是待调整的堆数组, len是数组的长度, elem是待调整的数组元素的位置//本函数功能是根据数组arr构建大根堆void HeapAdjust(int arr[],int len,int elem){    int Child;    for(;2*elem+1<len;elem=Child)    {        //子结点的位置=2*(父结点位置)+1        Child=2*elem+1;        //得到子结点中较大的结点        if(Child<len-1&&arr[Child+1]>arr[Child]) ++Child;        //如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点        if(arr[elem]<arr[Child])            swap(arr[elem],arr[Child]);        else            break; //否则退出循环    }}//堆排序算法void HeapSort(int arr[],int len){    //调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素    //len/2-1是最后一个非叶节点,此处"/"为整除    for(int elem=len/2-1;elem>=0;--elem)        HeapAdjust(arr,len,elem);    //从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素    for(int i=len-1;i>0;--i)    {        //把第一个元素和当前的最后一个元素交换,        //保证当前的最后一个位置的元素都是在现在的这个序列之中最大的        swap(arr[0],arr[i]);        //不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值        HeapAdjust(arr,i,0);    }}int main(){    int num[]={9,3,88,7,64,5,4,32,2,1,0,23,10,6,8};    int len=sizeof(num)/sizeof(int);    HeapSort(num,len);    for(int i=0;i<len;++i)        cout<<num[i]<<' ';    return 0;}

原创粉丝点击