数据结构:栈
文章目录
栈(stack)是一个特殊的线性表,是限定仅在一端通常是表尾)进行插入和删除操作的线性表。又称为后进先出(Last In First Out)的线性表,简称LIFO结构。
1.栈的相关概念
栈是仅在表尾进行插入、删除操作的线性表。
表尾(即an端)称为栈顶Top;表头(即ah端)称为栈底Base
插入元素到栈顶(即表尾)的操作,称为入栈。
从栈顶(即表尾)删除最后一个元素的操作,称为出栈。
栈的相关概念 | 描述 |
---|---|
定义 | 限定只能在表的一端进行插入和删除运算的线性表(只能在栈顶操作) |
逻辑结构 | 与同线性表相同,仍为一对一关系。 |
存储结构 | 用顺序栈或链栈存储均可,但以顺序栈更常见 |
运算规则 | 只能在栈顶运算,且访问结点时依照进先出 (LIFO) 的原则。 |
实现方式 | 关键是编写入栈和出栈函数,具体实现依顺序栈或链栈的不同而不同。 |
2.栈和一般线性表的区别
栈与一般线性表的区别:仅在于运算规则不同。
一般线性表 | 栈 |
---|---|
逻辑结构:一对一 | 逻辑结构:一对一 |
存储结构:顺序表、链表 | 存储结构:顺序栈、链栈 |
随机存取 | 运算规则:后进先出 (LIFO) |
3.栈的抽象数据类型与类型定义
操作名称 | 描述 | 初始条件 | 操作结果 |
---|---|---|---|
InitStack(&S) | 初始化操作 | 栈S已存在 | 构造一个空栈S |
GetTop(S, &e) | 取栈顶元素 | 栈S已存在且非空 | 用e返回S的栈顶元素 |
DestroyStack(&S) | 销毁栈操作 | 栈S已存在 | 栈S被销毁 |
ClearStack(&S) | 栈置空操作 | 栈S已存在 | 将S清为空栈 |
Push(&S, e) | 入栈操作 | 栈S已存在 | 插入元素e为新的栈顶元素 |
Pop(&s, &e) | 出栈操作 | 栈S已存在且非空 | 删除S的栈顶元素an,并用e返回其值 |
StackEmpty(S) | 判定S是否为空栈 | 栈S已存在 | 若栈S为空栈,则返回TRUE,否则FALSE |
StackLength(S) | 求栈的长度 | 栈S已存在 | 返回S的元素个数,即栈的长度 |
4.顺序栈的表示和实现
4.1顺序栈的定义
存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元依次存放自栈到栈顶的数据元素。栈底一般在低地址端。
- 附设top指针,指示栈顶元素在顺序栈中的位置。
- 另设base指针,指示栈底元素在顺序栈中的位置。
//顺序栈的定义
#define Max_Size 100
typedef int SElemType;
typedef struct {
SElemType* top; //栈顶指针
SElemType* base; //栈底指针
int stacksize; //栈的最大可用容量
}SqStack;
4.2顺序栈的初始化
//顺序栈的初始化
bool InitSqStack(SqStack* S) {
//为栈分配一个内存空间
S->base = (SElemType)malloc(Max_Size*sizeof(SElemType));
if(!S->base) {
return false;
}
S->top = S->base;
S->stacksize = Max_Size;
return true;
}
//判断栈是否为空
bool StackEmpty(SqStack* S) {
if(S->base == S->top) {
return true;
}
return false;
}
4.3一些补充算法
4.3.1求顺组栈的长度
int StackLength(SqStack* S) {
return S->top - S->base;
}
4.3.2清空顺序栈
//清空顺序栈
void CleerStack(SqStack* S) {
if(S->base) {
S->top = S->base;
}
}
4.3.3销毁顺序栈
//销毁顺序栈
void DestoryStack(SqStack* S) {
if(S->base) {
S->stacksize = 0;
S->top = S->base = NULL;
}
}
4.4顺序栈入栈
- 判断是否栈满,若满则出错(上溢)
- 元素e压入栈顶
- 栈顶指针加1
void Push(SqStack* S,SElemType e) {
if(S->top - S->base == S->stacksize) {
return;
}
S->top++ = e;
}
4.5顺序栈的出栈
- 判断是否栈空,若空则出错(下溢)
- 获取栈顶元素e
- 栈顶指针减1
//顺序栈的出栈
void Pop(SqStack* S, SElemType e) {
if(S->top == S->base) {
return;
}
e = --S->top;
}
5.链栈的表示和实现
5.1链栈的表示
链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct StackNode{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
LinkStack S;
- 链表的头指针就是栈顶
- 不需要头结点
- 基本不存在栈满的情况
- 空栈相当于头指针指向空
- 插入和删除仅在栈顶处执行
5.2链栈的初始化
void InitStack(LinkStack &S )
//构造一个空栈,栈顶指针置为空
S=NULL;
}
5.3判断链栈是否为空
// 判断链栈是否为空的函数
Status IsEmpty(LinkStack S) {
return S->top == NULL; // 如果栈顶指针为NULL,则栈为空
}
5.4链栈的入栈操作
// 链栈的入栈操作
Status Push(LinkStack S, SElemType e) {
LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode)); // 创建新节点
if (!new_node) {
return ERROR; // 内存分配失败
}
new_node->data = e; // 将元素e赋值给新节点的数据部分
new_node->next = S->top; // 新节点的next指向原栈顶
S->top = new_node; // 更新栈顶为新节点
return OK; // 入栈成功
}
5.5链栈的出栈操作
// 链栈的出栈操作
Status Pop(LinkStack S, SElemType* e) {
if (IsEmpty(S)) {
return ERROR; // 如果栈为空,出栈失败
}
LinkNode* temp = S->top; // 保存栈顶节点
S->top = S->top->next; // 将栈顶指向下一个节点
*e = temp->data; // 将出栈元素赋值给e
free(temp); // 释放原栈顶节点的内存
return OK; // 出栈成功
}