堆和栈的区别

本文探讨了堆和栈的区别,主要从内存管理的角度出发,详细阐述了栈的自动分配和释放,以及堆的动态申请和释放。接着,从数据结构角度解释了栈的FILO特性以及堆作为完全二叉树的性质。还提到了堆排序的应用,强调了堆排序对初始数据分布的适应性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆和栈的区别----内存

代码在内存种从高地址—>低地址分区为栈区,堆区,全局区,常量区,代码区

  • 栈区:由编译器进行管理,自动分配和释放,存放的是 函数调用过程中的各种参数,局部变量,返回值以及函数返回地址。栈区的好处是,执行效率高,速度快。
  • 堆区(heap) :用于程序 动态申请分配和释放空间,malloc和free,程序员申请的空间在使用结束后应该释放,则程序自动收回。好处是申请比较灵活,而且使用非常方便。
  • 全局(静态)存储区:分为 DATA(已经初始化),BSS(未初始化)段,DATA段存放的是全局变量和静态变量;
    BSS(未初始化)存放未初始化的全局变量和静态变量。 程序运行结束后自动释放,其中BSS(全部未初始化区)会被系统自动清零。
  • 文字常量区 :存放常量字符串,程序结束后由系统释放。
  • 程序代码段:存放程序的二进制代码。
int a = 0;    //全局初始化区
char *p1;     //全局未初始化区
int main()    //代码区
{
   int b;     //栈区(局部变量)
   char s[]="abc";  //s数组在栈区   'abc\0'在常量区
   char *p2;  //栈区(局部变量)
   char *p3 = "123456";  //指针p3在栈区(局部变量)   '123456\0'在常量区
   static int c = 0;    //全局(静态)初始化区
   p1 = (char *)malloc(10);  //分配的10字节区域在堆区   p1在全局区
   p2 = (char *)malloc(20);  //分配的20字节区域在堆区   p2在栈区
   strcpy(p1,"123456");  //'123456\0'在常量区  系统可能会把它和p3的字符放一起
   free(p1);
   free(p2);
} 

主要有以下几个区别:

1 申请方式:
Strack(栈): 由编译器自带分配释放,存放函数的参数值,局部变量等。
Heap(堆):程序员自己申请,并指名大小–>malloc函数。
2 申请后的系统响应
Strack(栈):只要栈剩余空间>所申请空间,都会提供。系统自由分配,速度快
Heap(堆):操作系统有记录空闲内存的链表:收到申请->遍历链表->寻找->申请空间的堆结点,速度较慢,容易产生内存碎片。
3 申请内存的大小限制
Strack(栈):向低地址扩展的数据结果,连续内存区域,栈获得的空间较小。
Heap(堆):向高地址扩展的,不连续内存区域;链表遍历方向为(低地址->高地址)。 堆获得空间灵活,空间也大。
4 存储内容
Strack(栈):第一进栈 :主函数中的下一条指令的地址–>函数的各个参数,参数由右往左进栈。–>函数的局部变量(静态变量不入栈)。调用结束后,顺序相反,局部变量先出栈。
Heap(堆):程序员自我安排。
5 分配方式
Strack(栈):栈有两种分配方式,静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配,动态分配由alloca函数进行分配,但栈的动态分配和堆是不同的,栈的动态内存由编译器进行释放,无需手工实现。
Heap(堆):堆都是动态分配的,没有静态分配的堆。

堆与栈 ---------数据结构

是一种运算受限的线性表,“先进后出”的特性(First In Last Out),简称 FILO。

栈分顺序栈和链式栈两种。栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。

#include<stdio.h>
#include<malloc.h>

#define DataType int
#define MAXSIZE 1024
struct SeqStack {
	DataType data[MAXSIZE];
	int top;
};

//栈初始化,成功返回栈对象指针,失败返回空指针NULL
SeqStack* initSeqStack() {
	SeqStack* s=(SeqStack*)malloc(sizeof(SeqStack));
	if(!s) {
		printf("空间不足\n");
		return NULL;
	} else {
		s->top = -1;
		return s;
	}
}

//判断栈是否为空
bool isEmptySeqStack(SeqStack* s) {
	if (s->top == -1)
		return true;
	else
		return false;
}

//入栈,返回-1失败,0成功
int pushSeqStack(SeqStack* s, DataType x) {
	if(s->top == MAXSIZE-1)
	{
		return -1;//栈满不能入栈
	} else {
		s->top++;
		s->data[s->top] = x;
		return 0;
	}
}

//出栈,返回-1失败,0成功
int popSeqStack(SeqStack* s, DataType* x) {
	if(isEmptySeqStack(s)) {
		return -1;//栈空不能出栈
	} else {
		*x = s->data[s->top];
		s->top--;
		return 0;
	}
}

//取栈顶元素,返回-1失败,0成功
int topSeqStack(SeqStack* s,DataType* x) {
	if (isEmptySeqStack(s))
		return -1;	//栈空
	else {
		*x=s->data[s->top];
		return 0;
	}
}

//打印栈中元素
int printSeqStack(SeqStack* s) {
	int i;
	printf("当前栈中的元素:\n");
	for (i = s->top; i >= 0; i--)
		printf("%4d",s->data[i]);
	printf("\n");
	return 0;
}

//test
int main() {
	SeqStack* seqStack=initSeqStack();
	if(seqStack) {
		//将4、5、7分别入栈
		pushSeqStack(seqStack,4);
		pushSeqStack(seqStack,5);
		pushSeqStack(seqStack,7);
		
		//打印栈内所有元素
		printSeqStack(seqStack);
		
		//获取栈顶元素
		DataType x=0;
		int ret=topSeqStack(seqStack,&x);
		if(0==ret) {
			printf("top element is %d\n",x);
		}
		
		//将栈顶元素出栈
		ret=popSeqStack(seqStack,&x);
		if(0==ret) {
			printf("pop top element is %d\n",x);
		}
	}
	return 0;
}

当前栈中的元素:
   7   5   4
top element is 7
pop top element is 7

堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点的值的完全二叉树被称之为堆。堆的这一特性称之为堆序性。因此,在一个堆中,根节点是最大(或最小)节点。如果根节点最小,称之为小顶堆(或小根堆),如果根节点最大,称之为大顶堆(或大根堆)。堆的左右孩子没有大小的顺序。
请添加图片描述

具体应用——堆排序
// array:待排序数组,len:数组长度
void heapSort(int array[],int len) {
	// 建堆
	makeMinHeap(array,len); 
	
	// 最后一个叶子节点和根节点交换,并进行堆调整,交换次数为len-1次
	for(int i=len-1;i>0;--i) {
		//最后一个叶子节点交换
		array[i]=array[i]+array[0];
		array[0]=array[i]-array[0];
		array[i]=array[i]-array[0];
        
        // 堆调整
		minHeapFixDown(array, 0, len-i-1);  
	}
}

堆排序快速排序在效率上是差不多的,但是堆排序一般优于快速排序的重要一点是数据的初始分布情况对堆排序的效率没有大的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值