栈:是一种运算受限的线性表,仅在表尾进行插入和删除操作,这一端叫做栈顶,另一端叫做栈底。数据结构特点就是先进后出(LIFO)LIFO的是 “Last In First Out” 的英文缩写。
- 入栈(Push)从栈顶添加元素
- 出栈(Pop)从栈顶移除元素
- 获取栈顶元素(peek):获取栈顶的元素,但不删除它。
- 判断栈是否为空(isEmpty):检查栈是否为空。
- 获取栈的大小(size):返回栈中元素的数量。
- 时间复杂度o(1)即它们都只需要一次操作就可以完成。这是因为栈是一种线性的数据结构,其元素的添加和移除都发生在同一个位置,即栈顶。
顺序栈:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define MaxSize 10
typedef struct{
int data[MaxSize];
int top;
} SqStack;
//初始化栈
void InitStack(SqStack *s)
{
s->top = -1;
}
//判断栈是否为空
bool StackEmpty(SqStack *S)
{
if(S->top == -1)//空
{
return true;
}else{
return false;
}
}
//入栈
bool Push(SqStack *S,int x)
{
if(S->top == MaxSize - 1)//栈满了
{
return false;
}
//S->data[++S->top] = x
S->top = S->top + 1;
S->data[S->top] = x;
return true;
}
//出栈
bool Pop(SqStack *S,int *x)
{
if(S->top == -1)//空栈就别出栈了
{
return false;
}
//*x = S->data[S->top--]; // 这玩意儿是先取值在减top 所以--在后面 这要注意
*x = S->data[S->top];
S->top = S->top - 1;
return true;
}
//获取栈顶元素
bool GetTop(SqStack *S,int *x)
{
if(S->top == -1)
{
return false;
}
*x = S->data[S->top];
return true;
}
//打印这个栈
void printStack(SqStack S)
{
printf("[");
while (!StackEmpty(&S)) {
int x = -1;
Pop(&S, &x);
printf(" %d ",x);
}
printf("]\n");
}
int main(int argc, const char * argv[]) {
SqStack S;
InitStack(&S);
Push(&S, 1);
Push(&S, 2);
Push(&S, 3);
Push(&S, 4);
Push(&S, 5);
Push(&S, 6);
int x = -1;
printStack(S);
Pop(&S, &x);
printStack(S);
return 0;
}
链栈:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
}*LiStack;
bool InitLiStack(LiStack* S)
{
*S = (LiStack)malloc(sizeof(LiStack));
if(*S == NULL){
return false;
}
(*S)->next = NULL;
return true;
}
bool Push(LiStack *S,int x)
{
struct LNode* new_node = (struct LNode*)malloc(sizeof(struct LNode));
new_node->data = x;
new_node->next = *S;
*S = new_node;
return true;
}
bool Pop(LiStack *S,struct LNode *x)
{
*x = **S;
(*S) = (*S)->next;
return true;
}
void printLiStack(LiStack S)
{
printf("[");
while (S != NULL) {
printf(" %d ",S->data);
S = S->next;
}
printf("]\n");
}
int GetTop(LiStack S)
{
if(S == NULL){
return -1;
}
return S->data;
}
int main(int argc, const char * argv[]) {
LiStack LS;
InitLiStack(&LS);
Push(&LS, 1);
Push(&LS, 2);
Push(&LS, 3);
Push(&LS, 4);
Push(&LS, 5);
Push(&LS, 6);
Push(&LS, 7);
Push(&LS, 8);
printLiStack(LS);
struct LNode x;
Pop(&LS, &x);
Pop(&LS, &x);
printf("x = %d\n",x.data);
printLiStack(LS);
printf("top = %d\n",GetTop(LS));
return 0;
}
链栈和顺序栈都是数据结构中的栈,它们的主要区别在于它们的实现方式和存储方式。
顺序栈是使用数组来实现的,它的优点是操作比较方便,缺点是需要分配连续的内存空间,可能会造成内存浪费。
链栈是使用链表来实现的,它的优点是可以动态地分配内存,不会造成内存浪费,缺点是操作相对于顺序栈来说稍微复杂一些。
相较于顺序栈,链栈一般不会出现栈满的情况。
栈是种比较简单的数据结构,在实际的生活中应用广泛。
-
栈式搜索:在解决迷宫问题、图的深度优先搜索等算法中,可以使用栈来记录搜索路径,从而找到从起点到终点的所有可能路径。
- 括号匹配:判断一段表达式是否合法,就需要使用栈。
- 浏览器的前进和后退:浏览器在处理浏览历史记录时,也是使用了一个栈结构,先进后出。
- 表达式计算:利用栈可以很容易地实现表达式的计算和括号匹配。
- 火车车厢重排:栈在火车车厢重排问题中也有应用,通过将车厢的排列顺序存储在一个栈中,可以方便地实现车厢的重新排列。
- 操作系统中的进程调度:在操作系统中,可以利用栈来保存待执行的进程信息,从而实现进程的调度。
- 路由器中的路由表:在路由器中,可以使用栈来存储路由表信息,从而确定数据包的最佳传输路径。
- Web服务器的HTTP请求处理:在Web服务器中,可以使用栈来处理HTTP请求,例如处理请求头和请求体。
- 其他方面各个的应用