栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO(Last In First Out)或先进后出FILO(First In Last Out)线性表。
栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
栈底(Bottom):是固定端,又称为表头。
空栈:当表中没有元素时称为空栈。
一般将插入和删除操作称为入栈和出栈。
栈是一种线性表,所以栈也有线性表的两种存储结构(顺序存储结构和链式存储结构)。
栈的顺序存储结构称为顺序栈,链式存储结构称为链栈。
顺序栈
利用一组地址连续的存储单元依次存放栈底到栈顶的数据元素,栈底位置固定不变,栈顶位置随着入栈和出栈操作而变化。
链栈
链栈是一种特殊的线性链表,和所有链表一样,是动态存储结构,无需预先分配存储空间。
typedef struct stack
{ //存放栈中元素的一维数组
STACK_DATA_TYPE data[STACK_SIZE];
int top; //存放栈顶元素的下标
}SeqStack;
S->top = -1;
栈顶元素下标 top 等于 -1 为空栈,所以只需将 top 赋值 -1 即可完成顺序栈的初始化。
if(S->top == -1)
return TRUE;
如果栈顶元素下标 top 等于 -1,则栈是空栈。
if(S->top == STACK_SIZE-1)
return TRUE;
如果栈顶元素下标 top 等于栈的大小(STACK_SIZE - 1),则栈已满。
S->top++;
S->data[S->top] = val;
先判断是否已经满栈,然后移动栈顶元素下标,再将数据放入栈中。
*val = S->data[S->top];
S->top--;
先判断栈是否为空,然后将栈顶元素下标对应的数据取出来,移动栈顶元素下标。
*val = S->data[S->top];
跟出栈的逻辑一样,只是没有移动栈顶元素的下标。
栈的顺序存储结构简称为顺序栈,和线性表类似,用一维数组来存储栈。根据数组是否可以根据需要增大,由可以分为静态顺序栈和动态顺序栈。
静态顺序栈实现如下:
#include
#include
#define TRUE 1
#define FALSE 0
#define STACK_SIZE 8
#define STACK_DATA_TYPE int
typedef struct stack
{ //存放栈中元素的一维数组
STACK_DATA_TYPE data[STACK_SIZE];
int top; //存放栈顶元素的下标
}SeqStack;
void InitStack(SeqStack *S)
{
S->top = -1;
}
int IsEmpty(SeqStack *S)
{
if(S->top == -1)
{
printf("栈为空\n");
return TRUE;
}
else
return FALSE;
}
int IsFull(SeqStack *S)
{
if(S->top == STACK_SIZE-1)
{
printf("栈已满\n");
return TRUE;
}
else
return FALSE;
}
int Push_Stack(SeqStack *S, STACK_DATA_TYPE val)
{
if(IsFull(S) == TRUE)
return FALSE;
S->top++;
S->data[S->top] = val;
return TRUE;
}
int Pop_Stack(SeqStack *S, STACK_DATA_TYPE *val)
{
if(IsEmpty(S))
return FALSE;
*val = S->data[S->top];
S->top--;
return TRUE;
}
int GetTop(SeqStack *S, STACK_DATA_TYPE *val)
{
if(IsEmpty(S))
return FALSE;
*val = S->data[S->top];
return TRUE;
}
void Print_Stack(SeqStack *S)
{
int i=0;
int size=0;
if(S->top == -1)
{
for(i=0; itop; i++)
{
printf("|_ _ _ _|\n"); //先打印栈上面为空的部分
}
size = S->top;
while(S->top != -1) //打印有数据的部分
{
printf("|__ %d __|\n", S->data[S->top]);
S->top--;
}
S->top = size;
}
}
int main()
{
SeqStack S; //不用使用malloc分配内存,因为栈结构体采用数组构建
InitStack(&S); //地址传递,保证每次对栈操作后,栈更新
IsEmpty(&S);
int val=0;
int i=0;
for(i=0; i<6; i++)
{
Push_Stack(&S, i+1);
}
IsEmpty(&S);
Print_Stack(&S);
for(i=0; i<2; i++)
{
Pop_Stack(&S, &val); //地址传递
printf("%d ", val);
}
printf("\n");
Print_Stack(&S);
GetTop(&S, &val);
printf("栈顶元素是:%d\n", val);
return 0;
}
@server:~/test/log/list/stack/array$ gcc -o stack stack.c -g
@server:~/test/log/list/stack/array$ ./stack
栈为空
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|__ 6 __|
|__ 5 __|
|__ 4 __|
|__ 3 __|
|__ 2 __|
|__ 1 __|
6 5
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|__ 4 __|
|__ 3 __|
|__ 2 __|
|__ 1 __|
栈顶元素是:4
#include
#define MAXSIZE 50
#define ElemType int
typedef struct {
ElemType data[MAXSIZE];
int top;
}sqStack;
void InitStack(sqStack &S){
S.top = -1;
}
bool IsEmpty(sqStack &S){
if(S.top == -1){
return true;
}else{
return false;
}
}
bool Push_Stack(sqStack &S,ElemType x){
if(S.top == MAXSIZE - 1){
return false;
}
S.data[++ S.top] = x;
return true;
}
bool Pop(sqStack &S, ElemType &x){ //使用引用&
if(S.top == -1){
return false;
}
x = S.data[S.top --];
return true;
}
bool GetTop(sqStack &S,ElemType &x){
if(S.top == -1){
return false;
}
x = S.data[S.top];
return true;
}
int main()
{
sqStack S;
InitStack(S);
printf("此时栈顶指针是:%d\n",S.top);
Push_Stack(S,1);
Push_Stack(S,2);
int x;
GetTop(S,x);
printf("获取栈顶元素:%d\n",x);
Pop(S,x); //实现部分使用引用&
printf("弹出栈顶元素:%d\n",x);
Pop(S,x);
printf("弹出栈顶元素:%d\n",x);
if(IsEmpty(S)){
printf("当前为空栈\n");
}else {
printf("当前栈不为空\n");
}
return 0;
}
@server:~/test/log/list/stack/array$ g++ -o gstack gstack.cpp -g
@server:~/test/log/list/stack/array$ ./gstack
此时栈顶指针是:-1
获取栈顶元素:2
弹出栈顶元素:2
弹出栈顶元素:1
当前为空栈
动态顺序栈实现如下:
#include
#include
#define TRUE 1
#define FALSE 0
#define STACK_SIZE 5
#define STACK_DATA_TYPE int
typedef struct stack
{ //存放栈中元素的一维数组
STACK_DATA_TYPE data[STACK_SIZE];
int top; //存放栈顶元素的下标
}SeqStack, *PSeqStack;
SeqStack* InitStack(void)
{
SeqStack *S = (SeqStack*)malloc(sizeof(SeqStack));
if(NULL != S)
{
S->top = -1;
return S;
}
else
{
printf("Memory allocate fail!\n");
exit(0);
}
}
void Destroy_Stack(PSeqStack *S)
{
PSeqStack PS = *S;
if(NULL != PS)
{
free(PS);
PS = NULL;
}
*S = NULL;
return;
}
int IsEmpty(SeqStack *S)
{
if(S->top == -1)
{
printf("栈为空\n");
return TRUE;
}
else
return FALSE;
}
int IsFull(SeqStack *S)
{
if(S->top == STACK_SIZE-1)
{
printf("栈已满\n");
return TRUE;
}
else
return FALSE;
}
int Push_Stack(SeqStack *S, STACK_DATA_TYPE val)
{
if(IsFull(S) == TRUE)
return FALSE;
S->top++;
S->data[S->top] = val;
return TRUE;
}
int Pop_Stack(SeqStack *S, STACK_DATA_TYPE *val)
{
if(IsEmpty(S))
return FALSE;
*val = S->data[S->top];
S->top--;
return TRUE;
}
int GetTop(SeqStack *S, STACK_DATA_TYPE *val)
{
if(IsEmpty(S))
return FALSE;
*val = S->data[S->top];
return TRUE;
}
void Print_Stack(SeqStack *S)
{
int i=0;
int size=0;
if(S->top == -1)
{
for(i=0; itop; i++)
{
printf("|_ _ _ _|\n"); //先打印栈上面为空的部分
}
size = S->top;
while(S->top != -1) //打印有数据的部分
{
printf("|__ %d __|\n", S->data[S->top]);
S->top--;
}
S->top = size;
}
}
int main()
{ //不建议使用该方法
SeqStack *S = InitStack(); //使用指针,动态分配内存
IsEmpty(S);
int val=0;
int i=0;
for(i=0; i<3; i++)
{
Push_Stack(S, i+1);
}
IsEmpty(S);
Print_Stack(S);
for(i=0; i<2; i++)
{
Pop_Stack(S, &val);
printf("%d ", val);
}
printf("\n");
Print_Stack(S);
GetTop(S, &val);
printf("栈顶元素是:%d\n", val);
return 0;
}
@server:~/test/log/list/stack/array$ gcc -o test test.c -g
@server:~/test/log/list/stack/array$ ./test
栈为空
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|__ 3 __|
|__ 2 __|
|__ 1 __|
3 2
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|_ _ _ _|
|__ 1 __|
栈顶元素是:1
编译的时候报:error: expected ‘;’, ‘,’ or ‘)’ before ‘&’ token
原因:
C语言中是不存在引用的,也就是说C语言中&表示的不是引用,仅仅是取地址符。
解决:
第一种:用指针来取代引用,在主函数中传进地址
第二种:将代码保存成.cpp文件(c++中支持引用)
栈的链式存储结构成为链栈,是运算受限的单链表。其插入和删除操作只能在表头位置上进行。因此,链栈没有必要像单链表那样附加头结点,栈顶指针top就是链表的头指针。
typedef struct StackNode //链栈结点
{
ElemType data;
struct StackNode *next;
}Stack_Node;
typedef struct stack //链栈结构
{
Stack_Node *top; //栈顶
int length; //长度
}LinkStack;
S->top = NULL;
S->length = 0;
初始化栈顶指针和链栈长度。
if(S->length == 0)
return TRUE;
当链栈长度等于0的时候为空栈,也可以判断 top 是否为 NULL;
Stack_Node *p = (Stack_Node*)malloc(sizeof(Stack_Node));
p->data = val;
p->next = S->top; //栈顶赋值给p->next
S->top = p; //新元素作为栈顶
S->length++; //链表长度加1
首先将栈顶 top 赋值给 p->next,然后将 p 作为栈顶指针,链栈长度加一。
Stack_Node *p = S->top; //标记栈顶
*val = p->data; //取出栈顶元素
S->top = p->next; //栈顶下移一个结点
S->length--; //长度减1
free(p);
*val = S->top->data;
#include
#include
#define FALSE 0
#define TRUE 1
typedef int ElemType;
typedef struct StackNode //链栈结点
{
ElemType data;
struct StackNode *next;
}Stack_Node;
typedef struct stack //链栈结构
{
Stack_Node *top; //栈顶
int length; //长度
}LinkStack;
void Init_Link_Stack(LinkStack *S)
{
S->top = NULL;
S->length = 0;
}
int IsEmpty(LinkStack *S)
{
if(S->length == 0)
return TRUE;
else
return FALSE;
}
int Push_Stack(LinkStack *S, ElemType val)
{
Stack_Node *p = (Stack_Node*)malloc(sizeof(Stack_Node));
if(p == NULL)
{
printf("Memory allocate fail!\n");
return FALSE;
}
p->data = val;
p->next = S->top; //栈顶赋值给p->next
S->top = p; //新元素作为栈顶
S->length++; //链表长度加1
return TRUE;
}
int Pop_Stack(LinkStack *S, ElemType *val)
{
if(IsEmpty(S) == TRUE)
{
return FALSE;
}
Stack_Node *p = S->top; //标记栈顶
*val = p->data; //取出栈顶元素
S->top = p->next; //栈顶下移一个结点
S->length--; //长度减1
free(p);
return TRUE;
}
int Get_Top(LinkStack *S, ElemType *val)
{
if(IsEmpty(S) == TRUE)
return FALSE;
*val = S->top->data;
return TRUE;
}
void Print_Stack(LinkStack *S)
{
int len=0;
Stack_Node *p = S->top; //标记栈顶
if(IsEmpty(S))
{
printf("栈为空\n");
}
len = S->length; //标记长度
while(S->length != 0)
{
printf("|__%d__|\n", S->top->data);
S->top = S->top->next;
S->length--;
}
S->top = p; //还原到操作前的栈顶和长度
S->length = len;
}
int main()
{
int i=0;
int val=0;
int len=0;
LinkStack S;
Init_Link_Stack(&S);
IsEmpty(&S);
printf("请输入入栈长度:");
scanf("%d", &len);
for(i=0; i
@server:~/test/log/list/stack/list$ gcc -o liststack liststack.c -g
@server:~/test/log/list/stack/list$ ./liststack
请输入入栈长度:5
|__5__|
|__4__|
|__3__|
|__2__|
|__1__|
请输入出栈长度:3
5 4 3
|__2__|
|__1__|
栈顶元素为:2
参考
https://blog.csdn.net/qq_42451060/article/details/82832246?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link