文章目录
一. 栈的基本概念
- 栈首先也是线性表,只是栈是一个受限的线性表.
- 栈具有前驱和后继的关系.
- 插入只能插入到栈顶,删除也是
- 栈的数据入口和出口相同,都是栈顶,所以栈后进先出
二. 栈的特性
LIFO
后进先出- 出栈和入栈只有一个入口,就是栈顶
三. 基于顺序存储的栈结构
① 顺序存储的栈的概念
栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表.顺序栈的存储结构是:利用一组地址连续的内存单元依次存放自栈底到栈顶的数据元素,同时设定top只是栈顶元素在顺序表中的位置
② 顺序存储栈的实现
因为栈是一种特殊的线性表,所以栈的顺序存储可以通过顺序线性表来实现
③ 使用数组模拟栈的顺序存储
栈顶放到数组的后面,这样数据插入的时候,不用频繁的移动
实现部分 SeqStack.h
#pragma once
#include <stdlib.h>
#include <stdio.h>
#define MAX_SIZE 1024
#define SEQ_STACK_TRUE 1
#define SEQ_STACK_FALSE 0
// 使用数组模拟栈操作,栈使用顺序存储来实现
typedef struct SeqStack
{
void *data[MAX_SIZE];
int size;
} SeqStack;
// 栈的操作
SeqStack *init_seq_stack();
// 入栈
void push_seq_stack(SeqStack *stack, void *data);
// 出栈
void pop_seq_stack(SeqStack *stack);
// 返回栈顶元素
void *top__seq_stack(SeqStack *stack);
// 判断是否为空
int is_empty(SeqStack *stack);
// 获取栈中元素个数
int get_size(SeqStack *stack);
// 清空栈
void clear_seq_stack(SeqStack *stack);
// 销毁栈
void destroy_seq_stack(SeqStack *stack);
SeqStack.c
#include "SeqStack.h"
// 栈的操作
SeqStack *init_seq_stack()
{
SeqStack *stack =(SeqStack*) malloc(sizeof(SeqStack));
// 这里分配内存的时候数组有没有分配内存呢,可以查看一下seqStack的大小
//printf("sizeof(SeqStack) = %zu\n", sizeof(SeqStack));
if (stack != NULL)
{
// 数组初始化
for (int i = 0; i < MAX_SIZE; i++)
{
stack->data[i] = NULL;
}
stack->size = 0;
}
return stack;
}
// 入栈
void push_seq_stack(SeqStack *stack, void *data)
{
if (stack->size == MAX_SIZE)
{
return;
}
if (stack != NULL && data != NULL)
{
stack->data[stack->size] = data;
stack->size++;
}
}
// 出栈
void pop_seq_stack(SeqStack *stack)
{
if (stack != NULL && stack->size > 0)
{
stack->data[stack->size - 1] = NULL;
stack->size--;
}
}
// 返回栈顶元素
void *top__seq_stack(SeqStack *stack)
{
if (stack != NULL && stack->size > 0)
{
return stack->data[stack->size - 1];
}
return NULL;
}
// 判断是否为空
int is_empty(SeqStack *stack)
{
if (stack != NULL)
{
return stack->size == 0 ? SEQ_STACK_TRUE : SEQ_STACK_FALSE;
}
return SEQ_STACK_TRUE;
}
// 获取栈中元素个数
int get_size(SeqStack *stack)
{
if (stack != NULL)
{
return stack->size;
}
return -1;
}
// 清空栈
void clear_seq_stack(SeqStack *stack)
{
if (stack != NULL)
{
for (int i = 0; i < stack->size; i++)
{
stack->data[i] = NULL;
}
stack->size = 0;
}
}
// 销毁栈
void destroy_seq_stack(SeqStack *stack)
{
if (stack != NULL)
{
free(stack);
}
}
测试代码:
#include "SeqStack.h"
typedef struct Person
{
char name[64];
int age;
} Person;
int main()
{
SeqStack* stack = init_seq_stack();
// 创建数据
Person p1 = { "P1",10 };
Person p2 = { "P2",20 };
Person p3 = { "P3",30 };
Person p4 = { "P4",40 };
Person p5 = { "P5",50 };
// 入栈
push_seq_stack(stack, (void *)&p1);
push_seq_stack(stack, (void *)&p2);
push_seq_stack(stack, (void *)&p3);
push_seq_stack(stack, (void *)&p4);
push_seq_stack(stack, (void *)&p5);
// 获取栈顶元素,然后出栈,看看是不是后进先出
Person *p;
for (int i = 0; i < 5; i++)
{
// 获取栈顶元素,出栈
p = (Person *)top__seq_stack(stack);
pop_seq_stack(stack);
printf("第 %d 个栈顶元素: 姓名: %s 年龄: %d \n", i + 1, p->name, p->age);
}
// 打印的顺序: P5,P$,P4,P2,P1
// 获取栈的大小,因为都出栈了,所以这里的大小为0
printf("栈的大小: %d\n", stack->size);
push_seq_stack(stack, (void*)&p1);
push_seq_stack(stack, (void *)&p2);
printf("栈的大小: %d\n", stack->size); // 2
// 清空栈
clear_seq_stack(stack);
printf("栈的大小: %d\n", get_size(stack));
destroy_seq_stack(stack);
system("pause");
return 0;
}
结果:
四. 基于链式存储的栈结构
① 链式栈(链栈基本概念)
使用链表实现栈,主要是用单链表,并且插入和删除操作只有一个入口,就是链表的第一个元素.
栈顶top第一个节点,next指向下一个节点,栈底节点的next指向NULL
② 链式栈的实现
LinkStack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LINK_SATCK_TRUE 1
#define LINK_STACK_FALSE 0
typedef struct LinkNode
{
struct LinkNode *next;
} LinkNode;
// 链式栈
typedef struct LinkStack
{
struct LinkNode head;
int size;
} LinkStack;
// 初始化函数
LinkStack *init_link_stack();
// 入栈
void push_link_stack(LinkStack *stack, LinkNode *data);
// 出栈
void pop_link_stack(LinkStack *stack);
// 返回栈顶元素
LinkNode *top_link_stack(LinkStack *stack);
// 栈是否为空
int is_empty_link_stack(LinkStack *stack);
// 返回栈的大小
int get_size_link_stack(LinkStack *stack);
// 清空栈
void clear_link_stack(LinkStack *stack);
// 销毁栈
void destroy_link_stack(LinkStack *stack);
LinkStack.c
#include "LinkStack.h"
// 初始化函数
LinkStack *init_link_stack()
{
// 为stack分配内存
LinkStack *stack = (LinkStack* )malloc(sizeof(LinkStack));
if (stack != NULL)
{
// 将头节点指向空,表示头尾重合没有其他的节点
stack->head.next = NULL;
stack->size = 0;
return stack;
}
return NULL;
}
// 入栈
void push_link_stack(LinkStack *stack, LinkNode *data)
{
// 插入到头部
// 新节点指向头部的后继节点
// 头部的后继节点指向新节点
if (stack != NULL && data != NULL)
{
data->next = stack->head.next;
stack->head.next = data;
stack->size++;
}
}
// 出栈
void pop_link_stack(LinkStack *stack)
{
if (stack != NULL && stack->size > 0)
{
// 先找到栈顶元素
LinkNode *nodeDel = stack->head.next;
// 将头部指向栈顶元素的下一个节点
stack->head.next = nodeDel->next;
stack->size--;
}
}
// 返回栈顶元素
LinkNode *top_link_stack(LinkStack *stack)
{
if (stack != NULL && stack->size > 0)
{
return stack->head.next;
}
return NULL;
}
// 栈是否为空
int is_empty_link_stack(LinkStack *stack)
{
if (stack != NULL)
{
return stack->size == 0 ? LINK_SATCK_TRUE : LINK_STACK_FALSE;
}
return LINK_STACK_FALSE;
}
// 返回栈的大小
int get_size_link_stack(LinkStack *stack)
{
if (stack != NULL)
{
return stack->size;
}
return -1;
}
// 清空栈
void clear_link_stack(LinkStack *stack)
{
if (stack != NULL)
{
stack->head.next = NULL;
stack->size = 0;
}
}
// 销毁栈
void destroy_link_stack(LinkStack *stack)
{
if (stack != NULL)
{
free(stack);
}
}
测试代码:
#include "LinkStack.h"
typedef struct Person
{
LinkNode *node;
char name[64];
int age;
} Person;
int main()
{
// 创建Person
Person p1, p2, p3, p4, p5;
int arrLen = sizeof(p1.name) / sizeof(p1.name[0]);
strcpy_s(p1.name, arrLen, "P1");
strcpy_s(p2.name, arrLen, "P2");
strcpy_s(p3.name, arrLen, "P3");
strcpy_s(p4.name, arrLen, "P4");
strcpy_s(p5.name, arrLen, "P5");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
// 创建栈,然后入栈
LinkStack *stack = init_link_stack();
push_link_stack(stack, (LinkNode *)&p1);
push_link_stack(stack, (LinkNode *)&p2);
push_link_stack(stack, (LinkNode *)&p3);
push_link_stack(stack, (LinkNode *)&p4);
push_link_stack(stack, (LinkNode *)&p5);
Person *p;
// 出栈,并且打印
for (int i = 0; i < 5; i++)
{
p = (Person *)top_link_stack(stack);
pop_link_stack(stack);
printf("第 %d 次,栈顶元素: 姓名: %s, 年龄: %d \n", i + 1, p->name, p->age);
}
// 出栈之后的大小为0
printf("出栈完成之后,栈大小: %d\n", stack->size);
// 再放入两个节点p1和p2
push_link_stack(stack, (LinkNode *)&p1);
push_link_stack(stack, (LinkNode *)&p2);
// 栈大小为2
printf("放入两个节点之后的栈大小: %d\n", stack->size);
p = (Person *)top_link_stack(stack);// 栈顶
printf("栈顶节点: 姓名: %s,年龄: %d\n", p->name, p->age);
// 清空栈
clear_link_stack(stack);
printf("清空栈之后的栈的大小: %d\n", stack->size);
destroy_link_stack(stack);
system("pause");
return 0;
}
结果: