【线性表】栈:线性栈、动态线性栈、链式栈的基本特性

栈(stack)是一种运算受限的线性表。其受限是指进行插入和删除操作仅仅发生在该线性表的尾部。


Table of Contents

线性栈

动态线性栈

链式栈


线性栈

栈的定义:

  1. 是一种只能在一端(一般是尾部)进行插入和删除操作的特殊线性表。
  2. 按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶;需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
  3. 栈也称为后进先出(List In First Out)的线性表,简称LIFO结构
  4. 它是一个线性表,也即,栈元素具有线性关系,即前驱后继关系
  5. 只不过它是一种特殊的线性表而已,进行插入和删除操作的只能在称为栈顶(top)的一端进行。另一端为栈底(bottom)。

什么是线性栈:

  1. 用一组地址连续的存储单元(即数组)依次存放栈底到栈顶的数据元素,栈底位置固定不变,栈顶位置随着入栈和出栈操作而变化。
  2. 线性栈的理解:立起来的数组,操作都在数组的最后元素位进行

线性栈的代码定义

#define MAXSIZE 100
typedef struct
{
	int data[MAXSIZE];
	int top;
}SeqStack;

特性:

  1. 栈中元素个数为零时称为栈。
  2. 栈的插入操作,一般称为进栈(PUSH),也称压栈、入栈。删除则称为出栈(POP),也称弹栈。

  1. 它的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
  2. 例如,递归时需要用到栈来记录断点;在浏览器的前进后退页也是利用栈来存储读取每个网页信息。

第一个线性栈

第一个线性栈
#include <stdio.h>
#define MAX 100

typedef struct
{
	int data[MAX];
	int top;
}stack;

int main()
{
	stack MyStack;

	//初始化栈
	MyStack.data[MAX] = 0;
	MyStack.top = -1;

	//进栈操作
	MyStack.data[++MyStack.top] = 100;  //栈顶指针往上移
	MyStack.data[++MyStack.top] = 200;

	//取数据
	printf("栈顶元素为:%d\n", MyStack.data[MyStack.top]);

	//出栈操作
	MyStack.top--;
	printf("栈顶元素为:%d\n", MyStack.data[MyStack.top]);

	return 0;
}

动态线性栈

为什么要引入动态线性栈?

  1. 在C语言中的数组要求在编译时必须确定数组的大小。
  2. 在利用数组做为线性栈的实现时,也会遇到数组容量不可以动态拓展的问题。
  3. 可以利用动态分配内存解决这个问题,即动态一维数组。

什么是动态线性栈?

  1. 动态的一维数组 + 栈的思想
  2. 动态申请一块内存,将栈中元素放入其中。当元素个数超过设定的最大长度时,可以在再动态申请更大的内存来存放元素。
  3. 通过动态内存申请返回的指针来以数组的形式访问栈中元素。

如何实现动态线性栈?

  • 使用malloc函数申请内存,使用realloc函数扩大内存;

第一个动态线性栈

#include <stdio.h>
#include  <stdlib.h>
#include  <assert.h>

typedef struct
{
	int* data;
	int top;
}stack;

int main()
{
	int size = 5;
	stack* MyStack = (stack*)malloc(sizeof(stack)); //为结构体分配内存
	assert(MyStack);
	
	//初始化
	MyStack->data = (int*)malloc(sizeof(int) * size); //为动态线性栈分配内存
	assert(MyStack->data != NULL);
	MyStack->top = -1;

	//压栈
	MyStack->data[++MyStack->top] = 100;
	MyStack->data[++MyStack->top] = 200;
	MyStack->data[++MyStack->top] = 300;

	//出栈
	MyStack->top--;
	printf("栈顶元素为:%d\n", MyStack->data[MyStack->top]);

	//重新分配大小
	size *= 2;
	MyStack->data = (int*)realloc(MyStack->data, size); //重新分配内存
	assert(MyStack->data != NULL); //注意,这将可能会导致原始的MyStack->data块内存泄露;这里仅作为演示,实际开发时慎用!

	MyStack->data[++MyStack->top] = 400;
	printf("栈顶元素为:%d\n", MyStack->data[MyStack->top]);
	return 0;
}


链式栈

什么是链式栈:

  1. 链式栈 = 单链表 + 栈的思想
  2. 链式栈的本质:倒立竖着的单链表
  3. 每次入栈一个元素,向链表中添加一个节点(相当于头插法),出栈一个元素,释放一个节点。

链式栈的本质就是一个“竖着”的链表!

特性:

  1. 利用单链表的头插法,可以避免每次在链表的尾部进行插入和删除,就要遍历整个链表来找到尾节点
  2. 在头部进行插入和删除时,只需根据头指针即可找到链表的首元素结点。而无需遍历链表。所以链式栈的出,入栈通过对链表进行头删和头插来实现。
  3. 单链表中常用的的头结点也就失去了意义,不再需要头结点的。

链式栈的代码定义

typedef struct node
{
	int data;
	struct node* next;
}StackNode;

第一个链式栈

#include <stdio.h>
#include  <stdlib.h>
#include  <assert.h>

typedef struct node
{
	int data;
	struct node* next;
}stack;

int main()
{
	stack* top = NULL; //设置一个栈顶指针,方便出栈、取栈操作
	stack* bottom = (stack*)malloc(sizeof(stack));
	assert(bottom != NULL);
	bottom->data = 100;
	bottom->next = NULL;
	top = bottom;

	stack* NodeAa = (stack*)malloc(sizeof(stack));
	assert(NodeAa != NULL);
	NodeAa->data = 200;
	NodeAa->next = bottom; //插入到bottom节点的前面,即头插法
	top = NodeAa;

	stack* NodeBb = (stack*)malloc(sizeof(stack));
	assert(NodeBb != NULL);
	NodeBb->data = 300;
	NodeBb->next = NodeAa;
	top = NodeBb;

	printf("栈顶元素:%d\n", top->data);

	//出栈
	stack* t = top;
	top = top->next;
	free(t);
	printf("栈顶元素:%d\n", top->data);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值