数据结构4线性表——顺序栈
前言:
本专栏属于数据结构相关内容,附带一些代码加深对一些内容的理解,为方便读者观看,本专栏内的所有文章会同时附带C语言和Python对应的代码,(可自行通过目录跳转到对应的部分)辅助不同主修语言的读者去更好的理解对应的内容,若是代码0基础的读者,可先去博主其他专栏学习一下基础的语法及知识点:
魔法天才的跳转链接:
C语言:C基础_Gu_shiwww的博客-CSDN博客
Python语言:python1_Gu_shiwww的博客-CSDN博客
其他数据结构内容可见:数据结构_Gu_shiwww的博客-CSDN博客
什么是栈
只能在一端进行插入和删除操作的线性表(又称为堆栈),进行插入和删除操作的一端称为栈顶(杯子顶部),另一端称为栈底(杯子底部)
栈遵循先进后出(first in last out)的原则
1 顺序栈的特点
逻辑结构:线性结构
物理结构:顺序结构
操作:创建、入栈、出栈、判空、判满
2 代码实现顺序栈
首先明确,栈如同我们生活中的泡腾片等,我们只能从一侧取出药片,在瓶口我们也只能看到最顶部的药片,所以我们在代码实现顺序栈的时候,可以设计一个top指针,指向我们的栈顶元素,这样栈的入栈和出栈操作都需要依靠栈顶指针top
C语言编程实现顺序栈
C.* 函数接口
#ifndef __SEQSTACK_H__
#define __SEQSTACK_H__typedef int datatype; //封装存入的数据的数据类型
typedef struct seqstack
{datatype *data; //指向数组首位的指针int maxlen; //保存栈的最大长度(数组元素个数)int top; //可以叫栈针,但本质是最后一个有效元素下标,和之前学的顺序表的last一样。
}seqstack_t, *seqstack_p;//1.创建一个空栈,len代表创建栈时的最大长度。
seqstack_t *createEmptySeqStack(int len);
//2.判断是否为满,满返回1 未满返回0
int isFullSeqStack(seqstack_t *p);
//3.入栈,data代表入栈的数据
int pushStack(seqstack_t *p, int data);
//4.判断栈是否为空
int isEmptySeqStack(seqstack_t *p);
//5.出栈,返回出栈数据
int popSeqStack(seqstack_t *p);#endif
C.1 创建空栈
//创建一个空栈,len代表创建栈时的最大长度
seqstack_t *createEmptySeqStack(int len)
{//1.申请空间存放栈的结构体seqstack_t *p = (seqstack_t *)malloc(sizeof(seqstack_t));if (NULL == p){perror("createEmptySeqStack p malloc err");return NULL;}//2.初始化p->maxlen = len; //保存栈的最大长度p->top = -1; //类似与之前顺序表的last,表示栈顶也就是最后一个有效元素的下标,此时没有数据入栈,可以置为-1,那么入栈第一个元素之后就可以加一变成0了,因为数组第一个元素下标为0。 p->data = (int *)malloc(sizeof(datatype) * len);if (NULL == p->data){perror("createEmptySeqStack p->data malloc err");return NULL;}return p;
}
创建空栈,len代表最大的数据个数,函数内部首先开辟一个结构体,结构体内部有maxlen(最大数据个数)、top(栈顶指针)、data(指向数组首地址元素的指针)。因为data是一个指针,可以直接将malloc开辟的空间的首地址赋给data,这样data就指向了开辟了maxlen长度的数组的首地址。下面跟着容错判断,看数组的开辟是否成功
C.2 判满
//判断是否为满,满返回1 未满返回0
int isFullSeqStack(seqstack_t *p)
{return p->top == p->maxlen -1;
}
top指向栈顶指针,但top实际还表示着最后一个有效元素的下标,当top与maxlen-1的值相同时,此刻开辟的空间已经存满了数据,栈为满,可以将判断语句的结果作为函数的返回值
C.3 入栈
//入栈,data代表入栈的数据
int pushStack(seqstack_t *p, int data)
{//1.容错判断if (isFullSeqStack(p)){printf("pushStack: isFullSeqStack\n");return -1;}//2.往上移动栈针p->top++;//3.将数据入栈p->data[p->top] = data;return 0;
}
首先容错判断,如果栈已满,不能再进行入栈操作,进入if语句给用户一个栈满的提示。若栈未满,栈顶指针top向后移动一个位置,数组对应下标的位置赋值为传进来的参数data
C.4 判空
//判断栈是否为空
int isEmptySeqStack(seqstack_t *p)
{return p->top == -1;
}
因为top代表栈顶数据的下标,当top为-1的时候,栈内数组无此下标,此刻栈内无任何数据,为空。可以将p->top == -1的结果作为此函数的返回值
C.5 出栈
//出栈
int popSeqStack(seqstack_t *p)
{//1.容错判断if (isEmptySeqStack(p)){printf("popSeqStack: isEmptySeqStack\n");return -1;}//2.往下移动栈针p->top--;//3.将栈要出栈数据返回return p->data[p->top + 1];
}
为保证代码的健壮性,出栈与入栈开始时要有相同操作,首先判断栈是否为空,空栈无数据可出。然后将top指针向下移动,此时top后一个位置的元素依旧存在,但是因为top指针的缘故,该数据不会被访问到,若想要拿到被删除数据的值,可以通过top+1得到。于是可以将p->data[p->top+1]作为此函数的返回值
C.6 完整代码(可运行)
#include<stdio.h>
#include <stdlib.h>typedef int datatype; //封装存入的数据的数据类型
typedef struct seqstack
{datatype *data; //指向数组首位的指针int maxlen; //保存栈的最大长度(数组元素个数)int top; //可以叫栈针,但本质是最后一个有效元素下标,和之前学的顺序表的last一样。
}seqstack_t, *seqstack_p;//创建一个空栈,len代表创建栈时的最大长度
seqstack_t *createEmptySeqStack(int len)
{//1.申请空间存放栈的结构体seqstack_t *p = (seqstack_t *)malloc(sizeof(seqstack_t));if (NULL == p){perror("createEmptySeqStack p malloc err");return NULL;}//2.初始化p->maxlen = len; //保存栈的最大长度p->top = -1; //类似与之前顺序表的last,表示栈顶也就是最后一个有效元素的下标,此时没有数据入栈,可以置为-1,那么入栈第一个元素之后就可以加一变成0了,因为数组第一个元素下标为0。 p->data = (int *)malloc(sizeof(datatype) * len);if (NULL == p->data){perror("createEmptySeqStack p->data malloc err");return NULL;}return p;
}//判断是否为满,满返回1 未满返回0
int isFullSeqStack(seqstack_t *p)
{return p->top == p->maxlen -1;
}//入栈,data代表入栈的数据
int pushStack(seqstack_t *p, int data)
{//1.容错判断if (isFullSeqStack(p)){printf("pushStack: isFullSeqStack\n");return -1;}//2.往上移动栈针p->top++;//3.将数据入栈p->data[p->top] = data;return 0;
}//判断栈是否为空
int isEmptySeqStack(seqstack_t *p)
{return p->top == -1;
}//出栈
int popSeqStack(seqstack_t *p)
{//1.容错判断if (isEmptySeqStack(p)){printf("popSeqStack: isEmptySeqStack\n");return -1;}//2.往下移动栈针p->top--;//3.将栈要出栈数据返回return p->data[p->top + 1];
}int main(int argc, char const *argv[])
{seqstack_t *p = createEmptySeqStack(5);for (int i = 1; i <= 6; i++)pushStack(p, i); //最后一次调用报:pushStack: isFullSeqStack,因为栈已经满了//只要栈不为空就出栈printf("出栈:");while(!isEmptySeqStack(p))//出栈的顺序是 5 4 3 2 1 ,因为栈的思想先进后出{printf("%d ",popSeqStack(p));}printf("\n");return 0;
}
Python语言编程实现
P.* 函数接口
class Stack:max_len = 32 # 保存栈的最大长度# 始终代表当前栈内最后一个有效元素的下标,称为栈顶指针top = -1data = [0] * max_len # 顺序栈的存储空间# 1、判断是否为满, 满返回True,未满返回Falsedef is_full(self):pass# 2. 入栈def push(self, data: int): # data代表入栈的数据pass# 3.判断栈是否为空def is_empty(self):pass# 4.出栈def pop(self):pass# 5. 清空栈def clear(self):pass# 6.获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)def get_top(self):pass# 7. 求栈的有限长度def get_length(self):pass
P.1 判满
# 1、判断是否为满, 满返回True,未满返回False
def is_full(self):return self.top + 1 == self.max_len
top作为栈顶数据的指针,同时也是栈顶数据的下标,下标从0开始,若栈顶下标+1与栈的最大长度相同,则代表栈内位置全部填满数据,可将该判断语句的结果作为函数返回值
P.2 入栈
# 2. 入栈
def push(self, data: int): # data代表入栈的数据if self.is_full():print("push error")returnself.top += 1self.data[self.top] = data
首先容错判断,若栈已满则无数据可以进入,未满则移动top指针到下一个位置,通过top下标访问data数据域,将传入的形参data写道对应下标位置
P.3 判空
# 3.判断栈是否为空
def is_empty(self):return self.top == -1
依旧使用top,top对应栈顶数据的下标,当它的值为-1时,证明栈内无任何元素,可以将该判断语句作为判空函数的返回值
P.4 出栈
# 4.出栈
def pop(self):if self.is_empty():print("pop error")returnself.top -= 1return self.data[self.top + 1]
出栈与入栈时相同首先进行容错判断。若栈不空直接将top值前移一位。若想得到出栈数据的值,可通过top+1得到该数据(因为top的移动只是有效下标的移动,并没有删除该数据,依旧可以通过下标进行访问,属于逻辑删除)
P.5 清空栈
# 5. 清空栈
def clear(self):self.top = -1
top作为最后有效元素的下标,只需将其置为-1,就可以在逻辑上清空整个栈
P.6 获取栈顶数据
# 6.获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)
def get_top(self):if self.is_empty():print("get_top error")returnreturn self.data[self.top]
容错判断判空,不为空则直接将top下标的值作为函数的返回值
P.7 求栈有效长度
# 7. 求栈的有限长度
def get_length(self):return self.top + 1
最简单的一集,top作为最后一个有效数据的下标,且下标从0开始,那top+1就是栈的有效长度。直接将top+1作为函数的返回值
P.8 完整代码(可运行)
class Stack:max_len = 32 # 保存栈的最大长度# 始终代表当前栈内最后一个有效元素的下标,称为栈顶指针top = -1data = [0] * max_len # 顺序栈的存储空间# 1、判断是否为满, 满返回True,未满返回Falsedef is_full(self):return self.top + 1 == self.max_len# 2. 入栈def push(self, data: int): # data代表入栈的数据if self.is_full():print("push error")returnself.top += 1self.data[self.top] = data# 3.判断栈是否为空def is_empty(self):return self.top == -1# 4.出栈def pop(self):if self.is_empty():print("pop error")returnself.top -= 1return self.data[self.top + 1]# 5. 清空栈def clear(self):self.top = -1# 6.获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针)def get_top(self):if self.is_empty():print("get_top error")returnreturn self.data[self.top]# 7. 求栈的有限长度def get_length(self):return self.top + 1if __name__ == '__main__':seq_stack = Stack()for i in range(6):seq_stack.push(i)print("top_data",seq_stack.get_top())print("stack_len",seq_stack.get_length())for _ in range(6):print(seq_stack.pop())