数据结构与算法 -- 栈 -- 顺序栈&&链栈

本文为作者学习b站上交版<<数据结构与算法>>, 结合清华大学出版社<<数据结构(C语言版)>> 的学习笔记, 部分内容来自于视频中的的PPT

栈的定义

栈 : 一个只能在栈顶进行插入何删除的线性表, 特征为 LIFO.
空栈 : 不含元素的空表
遵循LIFO(Last In First Out)原则的线性表

堆栈的表示和实现

栈的表示

在这里插入图片描述

顺序栈操作

#define TRUE 1 //正确
#define FALSE 0 //错误
#define OK 1 //执行成功
#define ERROR 0 //执行有误

#define INFEASIBLE -1 //不可执行
#define OVERFLOW -2 //溢出

typedef int Status; //函数执行的结果, 返回值为 int 类型

typedef int ElemType; //用 int 型元素表示任意类型的元素

#define STACK_INIT_SIZE 100 //初始存储空间
#define STACKINCREMENT 10 //存储空间不够的时候, 每次扩容增加的存储空间

typedef int SElemType;

typedef struct {
	SElemType* base; //栈底
	SElemType* top; //栈顶
	int stacksize; //当前可以使用的最大容量
}SqStack;

//代码来源 <<数据结构>> (清华大学出版社出版, 严蔚敏/吴伟民 编著)

base 为 NULL 则栈结构不存在
top 指向的是栈顶元素的下一个位置(下次入栈的位置)
top-1 指向出栈时下一个元素的取值位置
栈空 : top == base
栈满 : top >= base + stacksize

在这里插入图片描述

初始化

Status InitStack(SqStack& S){
	S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base) exit(OVERFLOW); //内存不足
	S.top = S.base; //空栈
	S.stacksize = STACK_INIT_SIZE; //初始存储空间
	return OK;
} //InitStack

//代码来源 <<数据结构>> (清华大学出版社出版, 严蔚敏/吴伟民 编著)

用malloc函数分配空间并进行判断, 将栈置空, 并且设置初始存储空间为 STACK_INIT_SIZE

销毁

Status StackDestory(SqStack& S)
{
	free(S.base); //将内存释放
	S.base = S.top = NULL; //指针置空
	S.stacksize = 0; //容量归零
	return OK; //返回状态码
} //StackDestory

销毁栈的代码如上.

判断是否为空

Status StackEmpty(SqStack S) {
	return (S.base == S.top);
} //StackEmpty

如果栈S没有初始化, 则无法编译成功(VS2019 : 使用了未初始化的局部变量)
栈为空的条件为 栈顶指针与栈尾指针重合, 所以直接返回 判断栈顶指针与栈尾指针重合的结果

长度

int StackLength(SqStack S)
{
	return (S.top - S.base);
}

这里直接返回 S.top - S.base 就是栈的长度
因为 : 两个指向同一个数组的指针相减, 得到的结果是两指针中间元素的个数

获得栈顶元素

Status GetTop(SqStack S, ElemType& e) {
	if (S.base == S.top) return ERROR; 
	//栈未初始化, 返回错误
	e = *(--S.top); 
	return OK;
} //GetTop

S.top指向的是栈顶元素的下一个元素, 所以在返回栈顶元素的时候应该将其先指向栈顶元素 即S.top–, 然后再将其指向的元素赋值给 e
因为栈 S 不能改变, 所以以值的方式传递, 元素e 以引用的方式传递.

入栈

Status Push(SqStack& S, SElemType e){ 
	//元素e插入到栈中, 成为新的栈顶
	if (S.top - S.base >= S.stacksize) {
		//栈满
		SElemType* newbase = (SElemType*)realloc(S.base,
			(STACK_INIT_SIZE + STACKINCREMENT) * sizeof(SElemType));
		if (!newbase)
			exit(OVERFLOW); //空间不够, 退出
		else
			S.base = newbase;
		S.top = S.base + S.stacksize;
		S.stacksize += STACKINCREMENT;
	}
	*S.top++ = e;
	return OK;
} //Push

//代码来源 <<数据结构>> (清华大学出版社出版, 严蔚敏/吴伟民 编著)

如果栈满了就将栈用realloc扩容. 每次扩容都增加10个元素的大小. 分配成功后, 将新的地址给S.base
然后将 e 的值赋给S.top(原先栈顶元素的下一个), 栈顶指针后移

出栈

Status Pop(SqStack& S, SElemType& e){
	//从栈顶读取数据到e, 栈中下一个元素所在的位置成为新的栈顶
	if (S.top == S.base)
		return ERROR; //栈为空
	e = *--S.top;
	return OK;
} // Pop

//代码来源 <<数据结构>> (清华大学出版社出版, 严蔚敏/吴伟民 编著)

由于 S.top 指向的是末尾元素的下一个元素, 所以, 我们只需要把s.top–即可, 下一次使用这一块内存的时候会给他重新赋值, 不需要有其他的操作了
注意 :
入栈 value->top, top++
出栈 top–; top-value, 出栈后可以理解为"这个位置空了" 元素还在 只是这个元素不再使用了, 在下一次赋值的时候就被覆盖了

遍历输出

Status TraversePrint(SqStack S)
{
	while (!StackEmpty(S)) {
		printf("%d ", *(--S.top));
	 }
	return OK;
}

注意, 这里要对S.top进行自减操作, 所以要用值传递.
每次都输出top指向的前一个位置的元素值, 直到 top 和 base 指针重合.
输出的顺序是从头到底
遵循先入后出原则

链栈操作

链栈

在这里插入图片描述
可以看出, 链栈每一个节点的指针域都指向其前方(下方)元素的next域, 而最后一个节点的指针域为NULL

初始化

typedef struct stack_node{
	ElemType data;
	struct stack_node* next;
}LinkStack;

Status InitLinkStack(LinkStack *stk){
	stk.next = NULL;
	return OK;
} //InitLinkStack

创造头节点.
将头结点的next置为空

判断是否为空

Status LinkStackEmpty(LinkStack* stk) {
	return stk->next == NULL;
}//LinkStackEmpty

我们已经在初始化的时候将链栈置为空栈. 所以, 如果栈为空栈, 那么stk->next == NULL 的结果为1, 否则为 0.把结果直接返回即可.

入栈

Status PUSH(LinkStack& stk, ElemType x){
	LinkStack top = (LinkStack)malloc(sizeof(LinkStack));
    //创造节点
	top->data = x; //数据赋值
	top->next = stk; //next 指向下方元素
	stk = top; //stk 指向栈顶元素
	return OK;
}

创造一个栈节点, 其数据域赋值为 x, 并将新的节点的next域指向其下面的节点.
然后令stk继续指向新的栈顶.

弹出栈

int POP(LinkStack& stk){
	//将栈顶元素赋值给 e 出栈
	int e = stk->data; //栈顶元素赋值给 e
	LinkStack p = stk; //中间变量 p 临时存放栈顶元素
	stk = stk->next; //栈顶指针前移
	free(p); //释放空间
	return e;
} //POP

销毁

Status DestoryLinkStack(LinkStack& stk) {
	while (!LinkStackEmpty(stk)){
		POP(stk);
	}
	free(stk);
	stk = NULL;
	return OK;
}//DestoryLinkStack

将所有元素全部弹出, 释放掉stk所占的内存之后将stk的指向置空

长度

int Length(LinkStack& stk)
{
	LinkStack temp = stk
	int length = 0; //初始长度为 0
	while (temp->next != NULL) {
		temp = temp->next; //当stk->next非空的时候, 也就是没有到栈底
		++length; //长度加一
	}
	return length; //返回栈长
}//Length

先用一个节点类型的变量存放stk, 用其进行遍历, 到栈底跳出循环, 返回长度.

获得栈顶元素

Status GETTOP(LinkStack& stk, ElemType& e){
	// 获得栈顶元素
	e = stk->data;
	return OK;
}

由于stk指向的就是栈顶元素, 所以直接返回 stk的data即可

遍历输出

Status TraversePrintLink(LinkStack S)
{
	LinkStack p = S;
	while (!LinkStackEmpty(p)) {
		printf("%d ", p->data);
		p = p->next;
	}
	return OK;
}

当p未指向栈底元素的时候, 输出p->data并且向栈底方向移动.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值