数据结构:栈

定义

栈(Stack)是只允许在一端进行插入或删除操作的线性表。遵循“后进先出”的原则。

  1. 栈顶:顾名思义是栈的顶端,可进行插入(入栈)与取出(出栈)操作。
  2. 栈底:同理:栈的底端,不允许进行插入或取出操作的位置。
  3. 假设某个栈S={a1,a2, … ,an},如上图所示,则a1为栈底元素,an为栈顶元素。由于只能在栈顶进行插入和删除操作,故进栈顺序为a1,a2, … ,an,出栈顺序为an, … ,a2,a1。故栈的操作特性是后进先出LIFO(Last In First Out),称为后进先出的线性表。
  4. 空栈:不含任何元素的空表。

栈的存储

  1. 存储方式:顺序存储(顺序栈,用顺序表为主体实现)与链式存储(链栈,用单链表为主体实现)
  2. 顺序栈:采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的元素,同时附设一个指针(top)指示当前栈顶的位置。下面为代码实现。

        

typedef struct Stack{
 int *arr;//一个数组用来存储数据
 int top;//栈顶位置
 int capacity;//栈的容量
}sta;
  1. 采用链式存储的栈称为链栈,链栈便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并且所有操作都是在单链表的表头进行的。这里算是链表的一个应用,链表我之前的代码因为重装系统电脑上没了,备份的数据又找不到了QAQ,等我过几天肝一肝再写出来。

栈上的基本操作及其代码实现

  • 初始化

为结构体中的数组分配内存空间,将栈顶位置放置到数组的第一个位置(arr[0]),栈的容量初始化为0。主要是给栈一个地址空间,将栈中的数据数据全部清空,便于后续的操作。

需要指出的是,这里的栈顶和示意图上的有所区别,示意图上的栈顶是指离栈最近的元素位置,而这里的栈顶位置设定的是要插入新元素的位置,即栈顶元素的下一位。例如对一个空栈,逻辑上栈顶位置下标应该为第0位,而初始化的代码却把(不存在的)第-1位看为空栈的栈顶,向它的下一位第0位插入元素。

void create_stack(sta* stack){
    if(stack==NULL)
        exit(-1);///退出进程
    stack->arr=NULL;//为数组分配空间
    stack->top=0;//表示栈顶元素的位置此时逻辑上栈顶元素的下标为-1,top始终指向栈顶元素的下一位
    stack->capacity=0;//栈的容量
}
  • 判空 

如果栈顶位置对应的下标(即结构体中top变量)为0,则为空栈。

int empty_check(sta* stack) {
	if (stack == NULL)
		exit(-1);
	if (stack->top > 0)
		return false;//非空
	else
		return true;//空栈
}
  • 进栈

首先判断该栈是否已满,如果满了需要将顺序表扩容。

然后在栈顶位置插入一个数,使之存入数组。再改变栈顶指向(指向新插入元素的下一位,使top自增即可)

void pushback(sta* stack, int x) {
	if (stack == NULL)
		exit(-1);
	if (stack->top == stack->capacity)//当栈满了的时候
	{
		int newcapacity = stack->capacity == 0 ? 4 : stack->capacity * 2;/*定义一个新变量来存储新的栈容量,如果旧的容量capacity为0,则赋值为4作为初始容量,
																		如果不是0,就双倍给下一个人(使新的容量赋值为旧容量的两倍)*/
		int* temp = (int*)realloc(stack->arr, sizeof(int) * newcapacity);//为变长数组扩容
		if(temp==NULL){
			perror("realloc fail!");//错误信息
			exit(-1);
		}
		stack->arr = temp;
		stack->capacity = newcapacity;//记录当前的栈容量。
	}
	stack->arr[stack->top] = x;//存入新数据
	stack->top++;//移动栈顶位置
}
  • 出栈

首先判断该栈是否为空栈,如果是空栈则无法进行弹出操作,直接return退出函数。

如果不是空栈,将栈顶位置向前移一位即可。这样就完成了数据的删除,如果有新的数据插入这个位置会把该位置的数据覆盖掉。

void popback(sta* stack) {//这里的形参可以多一个指针来记录被弹出的数据
	if (stack == NULL)
		exit(-1);
	if (stack->top > 0)
		stack->top--;
}
  • 读栈顶元素

直接返回arr[top]即可。

int gettop(sta* stack) {
	if (stack == NULL)
		exit(-1);
	if (stack->top > 0)
		return stack->arr[stack->top - 1];
}
  • 遍历栈

首先判断是否为空栈,如果为空退出函数。

若非空栈,从0到top位置遍历结构体成员中的数组即可。

void printf_stack(sta* stack) {
	if (stack == NULL)
		exit(-1);
	if (empty_check(stack)) {
		cout << "空栈";//输出提示
		return;
	}
	int cnt = stack->top - 1;
	while (cnt >= 0) {//遍历数组
		cout << stack->arr[cnt--]<<" ";
	}
	cout << endl;
}
  • 获取栈的长度

返回top变量即可,top的值也代表了栈的大小(长度)。

int gettop(sta* stack) {
	if (stack == NULL)
		exit(-1);
	if (stack->top > 0)
		return stack->top;
}
  • 销毁栈

栈的销毁,需要将动态数组的头指针 free 掉,结构体其他成员置0。

void erease_check(sta* stack) {
	if (stack == NULL)
		exit(-1);
	free(stack->arr);
	stack->top = 0;
	stack->capacity = 0;
	stack = NULL;
}

测试代码:(将部分函数进行调整使输出美观)

#include<iostream>

typedef struct Stack{
 int *arr;//一个数组用来存储数据
 int top;//栈顶位置
 int capacity;//栈的容量
}sta;

int main() {
	sta stack;
	cout << "以下检验初始化以及入栈"<<endl;
	int cnt = 8;
	create_stack(&stack);
	while (cnt--) {
		int x;
		printf("请输入要插入的数据x:");
		scanf_s("%d",&x);
		pushback(&stack, x);
	}
	printf_stack(&stack);
	cout << "以下检验出栈"<< endl;
	popback(&stack);
	printf_stack(&stack);
	cout << "以下检验判空"<<endl;
	if (empty_check(&stack))//判空stack
		cout << "true";
	else
		cout << "false";
	cout << endl;
	sta sta2;//新建一个栈
	create_stack(&sta2);//初始化新建栈
	if (empty_check(&sta2))//对新建栈判空
		cout << "true";
	else
		cout << "false";
	cout << endl;
	cout << "以下检验取栈顶元素" << endl;
	cout<<gettop(&stack)<<endl;
	//清空栈
	erease_check(&stack);
	erease_check(&sta2);
}

输出结果:

以上就是这几天的学习成果了,欢迎勘误与友好交流。

  • 相关链接

【C语言】栈(Stack)的实现(定义、入栈、出栈、销毁)|图解数据结构,超详细解析_c语言stack-CSDN博客

栈——栈的定义及基本操作(初始化、判空、进栈、出栈、遍历栈、销毁栈等)-CSDN博客

栈(计算机术语)_百度百科

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值