数据结构篇三:栈

栈的定义

栈是一种操作受限制的线性表,它只允许在一端进行插入和删除。绝大多数编程语言都有堆栈模型,它是一种局部变量回收机制,它是如何工作?讲完今天的栈,我们来分析下这种机制。

栈是有数组和一个栈顶指针构成(此处的指针不是c语言里的*p),该指针就是代表标记栈顶元素位置的。每次元素都只能从一端入栈,且只能从这一端出栈。很容易分析,它的入栈和出栈事件复杂度是0(1).下图是一个栈操作流程

在这里插入图片描述

栈的代码还是比较容易实现的,控制好一端插入和删除就可以了。主流上,有两种栈,顺序栈和链式栈。大学课本的顺序栈是定义好空间大小的,其实我们可以和c++的STL库一样,设计一个顺序栈的自动扩容版本。
至于链栈,我们为了保证入栈和出栈时间复杂度保持0(1),所以必须采用头插法进行模拟栈,如果是尾插法,还得每次走到最后面,当然,有人可能会问,我设计个循环双链表就可以了,可以是可以,不过,这不是更麻烦了吗?下面我将贴出顺序栈和链栈的核心代码。

顺序栈(可自动扩容)

顺序栈就是用数组模拟栈,为了设计方便,我们用数组的尾部模拟栈顶,每次入栈元素时,都视作插入一个元素到数组的末尾,然后更新栈顶指针,出栈时,我们就删除最后一个元素,模拟出栈,更新栈顶指针。

图示分析顺序栈

1.模拟入栈

在这里插入图片描述

入栈元素10,直接将10插入到数组最后,更新top指向。

2.模拟出栈

在这里插入图片描述

出栈就是直接将栈顶top指向的删除,top减去1.

//入栈操作
void push(struct Stack *stack,int data)
{
	//栈满了,自动扩容
	if (stack->top + 1 == stack->size)
	{
		int temp,*p;
		temp = stack->size;
		stack->size = stack->size * 2;
		p = (int *)malloc(sizeof(int)*stack->size);
		for (int i = 0; i < temp; i++)
		{
			p[i] = stack->data[i];
		}
		free(stack->data);
		stack->data = NULL;
		stack->data = p;
		stack->data[++stack->top] = data;
	}
	//不满,正常操作
	else {
		stack->data[++stack->top] = data;
	}
}
//出栈
int pop(struct Stack *stack)
{
	if (stack->top == -1)
	{
		return -999;
	}
	else {
		return stack->data[stack->top--];
	}
}

链式栈

链式栈就是链表,只不过规定了链表的一些插入和删除顺序,进而可以模拟栈的过程。

原理:在单链表的基础上,每次插入节点时,都采取头插法,用首节点模拟栈顶元素,当要插入时,直接插在首节点前面,然后讲栈顶指针指向插入的节点,删除操作时,控制只能删除链表最前面的节点,这样的两个控制,就很好的模拟了栈的特点。

图示分析链式栈

1.模拟入栈

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

入栈就是头插法,将新节点插入最前面作为栈顶元素

2.模拟出栈

在这里插入图片描述

出栈就是直接删除头节点,将新的头节点作为栈顶。

//入栈
void LinkStack_push(struct LinkStack * s, int data)
{
	struct Node *temp;
	temp = (struct Node*)malloc(sizeof(struct Node));
	temp->data = data;
	temp->next = s->head->next;
	s->head->next = temp;
	s->size++;
}
//出栈
int LinkStack_pop(struct LinkStack * s)
{
	if (s->head->next == NULL)
	{
		return -999;
	}
	else {
		struct Node *temp = s->head->next;
		int data = temp->data;
		s->head->next = temp->next;
		free(temp);
		temp = NULL;
		return data;
	}
}

看完了栈的实现,现在我们来分析下前面的问题,堆栈模型的垃圾回收机制。我还是直接上图举例子吧。

在这里插入图片描述

这个c语言,大家都应该会吧,首先我们的清楚函数定义的变量是局部变量,定义一个出来,就分配了指定类型大小的空间,此时的定义变量就是入栈操作,而函数结束执行完成后,栈会依次退栈操作,例如上面的操作,add函数执行完成后,sum释放,接着y释放,x释放,然后main函数结束后,result释放,num释放。好了,这个就是模拟一个简单的内存在栈模拟。

总结

栈看起来不常用,其实它应用于许多地方,在后面的递归,树的遍历非递归等,都可以用到栈。所以说,掌握栈是我们必须要做到的。

获取完整代码

我分别用C,C++,JAVA三种主流语言编写了完整代码,有需要的在微信公众号搜索考研稳上岸获取完整代码

数据结构练习(同样适用于考研)

微信小程序搜索计算机刷题
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值