栈与队列
概念
栈:只能在固定的一端进行操作;“先进后出”
-
栈顶:可以进行插入删除的一端
-
栈底:栈顶的对端
-
入栈(压栈):将节点插入栈顶之上
-
出栈(弹栈):将节点从栈顶剔除
队列:
-
队头:可以删除节点的一端
-
队尾:可以插入节点的一端
-
入队:将节点插入到队尾之后
-
出队:将队头节点从队列中剔除
顺序栈
顺序栈数据操作代码
//math3文件
----------------------------------------------------------------------------
sstack.h
----------------------------------------------------------------------------
#ifndef __SSTACK_H
#define __SSTACK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//定义数据的类型,可以是复杂的结构体,本案例使用int
/*
typedef struct Book
{
int id;
char *name;
int bookId;
char *author;
}DATA;
*/
typedef int DATA;
//顺序栈结构体
typedef struct
{
DATA *pData; //栈中元素的地址
int size; //顺序栈的大小(数组的大小)
int top; //栈顶元素下标
}SeqStack;
//初始化栈
int SStack_init(SeqStack* s, int size);
//判断是否栈满
int SStack_isFull(SeqStack* s);
//判断是否栈空
int SStack_isEmpty(SeqStack* s);
//入栈|压栈
int SStack_push(SeqStack* s, DATA data);
//出栈|弹栈(指定元素)
int SStack_pop(SeqStack* s, DATA *data);
//回收栈
int SStack_free(SeqStack* s);
#endif
----------------------------------------------------------------------------
sstack.c
----------------------------------------------------------------------------
#include "sstack.h"
//初始化栈
int SStack_init(SeqStack* s, int size)
{
//给栈中元素申请空间
s->pData = (DATA*)calloc(sizeof(DATA), size);
//校验
if(s->pData == NULL)
{
perror("内存申请失败!");
return -1;
}
//初始化
s->size = size;
s->top = -1; //空栈(元素个数为 top+1 )
return 0;
}
//判断是否栈满
int SStack_isFull(SeqStack* s)
{
return s->top + 1 == s->size;
}
//判断是否栈空
int SStack_isEmpty(SeqStack* s)
{
return s->top == -1;
}
//入栈|压栈
int SStack_push(SeqStack* s, DATA data)
{
if(SStack_isFull(s))
{
printf("栈满!\n");
return -1;
}
//操作栈
s->top++; //类似于顺序表的插入
s->pData[s->top] = data; //在更新后的top放数据
return 0;
}
//出栈|弹栈
int SStack_pop(SeqStack* s, DATA *data)
{
if(SStack_isEmpty(s))
{
printf("栈空!\n");
return -1;
}
//操作栈
*data = s->pData[s->top];
s->top--;
return 0;
}
//回收栈
int SStack_free(SeqStack* s)
{
if(s->pData)
{
free(s->pData);
s->pData = NULL;
}
s->top = -1;
}
----------------------------------------------------------------------------
sstack_main.c
----------------------------------------------------------------------------
#include "sstack.h"
int main(void)
{
SeqStack st;
SStack_init(&st,10);
register int i = 1;
for(; i <=9; i++)
{
SStack_push(&st,i);
}
if(-1 == SStack_push(&st,1024))
{
fprintf(stderr,"满栈,插入失败\n");
}
while(!SStack_isempty(&st))
{
DATA data = 0;
SStack_pop(&st,&data);
printf("%4d",data);
}
printf("\n");
SStack_free(&st);
return 0;
}
链式栈
链式栈数据操作代码
//math4文件
----------------------------------------------------------------------------
linkstack.h
----------------------------------------------------------------------------
#ifndef __LINKSTACK_H
#define __LINKSTACK_H
#include <stdio.h>
#include <stdlib.h>
//定义数据存储类型
typedef int DATA;
//定义链式栈节点
typedef struct node
{
DATA data; //数据域
struct node *next; //指向下一个节点指针
} NODE;
//定义链式栈(就是一个装链式表的容器)
typedef struct
{
NODE *pHead; //栈顶指针
int size; //元素个数
int sum; //记录节点个数
}LinkStack;
//初始化链式栈
int LStack_init(LinkStack *s, int num);
// 判断栈是否已满
int LStack_isfull(LinkStack *s);
// 判断栈是否为空
int LStack_isempty(LinkStack *s);
// 压栈/入栈
int LStack_push(LinkStack *s,DATA data);
// 弹栈/出栈
int LStack_pop(LinkStack *s,DATA *data);
// 回收栈
int LStack_free(LinkStack *s);
#endif
----------------------------------------------------------------------------
linkstack.c
----------------------------------------------------------------------------
#include "linkstack.h"
//初始化链式栈
int LStack_init(LinkStack *s, int num)
{
s->pHead = NULL;
s->size = num;
s->num = 0; //用来计数
return 0;
}
// 判断栈是否已满
int LStack_isfull(LinkStack *s)
{
return s->num == s->size;
}
// 判断栈是否为空
int LStack_isempty(LinkStack *s)
{
return s->num == 0;
}
// 压栈/入栈
int LStack_push(LinkStack *s,DATA data)
{
//判断是否栈满
if(LStack_isfull(s))
{
return -1;
}
NODE* p = s->pHead;
if(!p)
{
return -1;
}
//给新节点赋初值,采用头插法
p->data = data;
p->next = s->pHead;
s->pHead = p;
(s->num)++; //计数
return 0;
}
// 弹栈/出栈
int LStack_pop(LinkStack *s,DATA *data)
{
//判断是否栈空
if(LStack_isempty(s))
{
return -1;
}
//创建一个空节点指向栈顶
NODE* p = s->pHead;
if(!p)
{
return -1;
}
//取出栈顶数据,然后栈顶向下移动
//注意区分 pHead:栈顶指针 next:链表指针 s:栈 p:链表
*data = p->data;
s->pHead = p->next;
free(p); //思考:为什么不是free(s)
//取出后可以释放空间
(s->num)--;
return 0;
}
// 回收栈(本质:回收链表节点)
int LStack_free(LinkStack *s)
{
NODE* p = s->pHead, *q = NULL;
while(p)
{
q = p;
p = p->next;
free(q);
}
s->pHead = NULL;
s->num = 0;
return 0;
}
----------------------------------------------------------------------------
linkstack_main.c
----------------------------------------------------------------------------
#include "linkstack.h"
int main(void)
{
LinkStack st;
LStack_init(&st,10);
register int i = 1;
//入栈
for(; i <= 10; i++)
{
LStack_push(&st,i);
}
if(-1 == LStack_push(&st,1024))
{
fprintf(stderr,"满栈,插入失败\n");
}
//出栈
while(!LStack_isempty(&st))
{
DATA data = 0;
LStack_pop(&st,&data);
printf("%4d",data);
}
printf("\n");
//回收栈
LStack_free(&st);
return 0;
}
顺序队列
顺序队列数据操作代码
//math5文件
--------------------------------------------------------------------------------------------------
squeue.h
--------------------------------------------------------------------------------------------------
#ifndef __SQUEUE_H
#define __SQUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int DATA;
//创建顺序队列
typedef struct
{
DATA *pData; //队列入口
int size; //队列总容量
int head; //队头元素下标
int tail; //队尾元素下标
}SQueue;
//初始化队列
int SQ_init(SQueue *q, int num);
// 判断顺序队列是否队满
int SQ_isfull(SQueue *q);
// 判断顺序队列是否队空
int SQ_isempty(SQueue *q);
// 顺序队列插入数据
int SQ_push(SQueue *q,DATA data);
// 顺序队列输出数据
int SQ_pop(SQueue *q,DATA *data);
// 回收顺序队
int SQ_free(SQueue *q);
#endif
--------------------------------------------------------------------------------------------------
squeue.c
--------------------------------------------------------------------------------------------------
#include "squeue.h"
//初始化队列
int SQ_init(SQueue *q, int num)
{
//创建队列空间
q->pData = (DATA*)calloc(sizeof(DATA),num);
if(q->pData == NULL)
{
return -1;
}
q->size = num;
q->head = q->tail = 0; //空的队列,后期再插入元素
return 0;
}
// 判断顺序队列是否队满
int SQ_isfull(SQueue *q)
{
//队头下标始终为0
return (q->tail + 1) % q->size == q->head;
}
// 判断顺序队列是否队空
int SQ_isempty(SQueue *q)
{
return q->head == q->tail;
}
// 顺序队列插入数据
int SQ_push(SQueue *q,DATA data)
{
//判断是否满队
if(SQ_isfull(q))
{
return -1;
}
类似于栈,看图,先全部集中到队头,插入时 tail 会变化(逐步往后移动),然后打印的时候从 head 开始(依次往后移动)
其实本质就是尾插法
q->pData[q->tail] = data;
//(q->tail+1):下标加1
//(q->tail+1) % q->size:防止越界
q->tail = (q->tail + 1) % q->size;
//若不循环:
return 0;
}
// 顺序队列输出数据
int SQ_pop(SQueue *q,DATA *data)
{
if(SQ_isempty(q))
{
return -1;
}
*data = q->pData[q->head];
q->head = (q->head + 1) % q->size;
return 0;
}
// 回收顺序队
int SQ_free(SQueue *q)
{
if(q->pData)
{
free(q->pData);
q->pData = NULL;
}
q->head = q->tail = 0;
}
链式队列
链式队列数据操作代码
//math6文件
--------------------------------------------------------------------------------------------------
linkSqueue.h
--------------------------------------------------------------------------------------------------
#ifndef __SQUEUE_H
#define __SQUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int DATA;
//定义链式队列节点
typedef struct node
{
DATA data;
struct node *next;
}NODE;
//定义链式队列
typedef struct
{
NODE *pHead; //头指针
NODE *pTail; //尾指针
int size; //队列当前元素个数
int num; //计数
}LinkQueue;
//初始化链式队列
void LQ_init(LinkQueue *, int);
//判断链式队列是否队满
int LQ_isfull(LinkQueue *);
//判断链式队列是否队空
int LQ_isempty(LinkQueue *);
//链式队列插入数据
int LQ_push(LinkQueue *, DATA);
//链式队列输出数据
int LQ_pop(LinkQueue *, DATA *);
//回收链式队列
int LQ_free(LinkQueue *);
#endif
--------------------------------------------------------------------------------------------------
linkSqueue.c
--------------------------------------------------------------------------------------------------
#include "linkSqueue.h"
//初始化链式队列
void LQ_init(LinkQueue *q,int size)
{
q->pHead = q->pTail = NULL;
q->size = size;
q->num = 0;
}
//判断链式队列是否队满
int LQ_isfull(LinkQueue *q)
{
return q->num == q->size;
}
//判断链式队列是否队空
int LQ_isempty(LinkQueue *q)
{
return q->num == 0;
}
//链式队列插入数据
int LQ_push(LinkQueue *q,DATA data)
{
//检验是否队满
if(LQ_isfull(q))
{
return -1;
}
//创建新节点并且初始化
NODE* pNew = (NODE*)malloc(sizeof(NODE));
if(!pNew)
{
return -1;
}
pNew->data = data;
pNew->next = NULL;
参考顺序队列思想
//第一种情况,链表为空
if(!(q->pTail))
{
q->pHead = q->pTail = pNew;
}
else //第二种情况,链表不为空
{
q->pTail->next = pNew;
q->pTail = pNew;
}
q->num++;
return 0;
}
//链式队列输出数据
int LQ_pop(LinkQueue *q,DATA *data)
{
//判断是否队空
if(LQ_isempty(q))
{
return -1;
}
//只要队列非空,就取首节点以及数据
NODE* pNew = q->pHead;
*data = pNew->data;
//第一种情况,队列只有一个节点
if(pNew == q->pTail)
{
q->pHead = q->pTail = NULL;
}
else //第二种情况,队列有多个节点
{
p->pHead = pNew->next;
}
free(pNew);
q->num--;
return 0;
}
//回收链式队列
int LQ_free(LinkQueue *q)
{
NODE* pNew = q->pHead, *p = NULL;
while(pNew)
{
p = pNew;
pNew = pNew->next;
free(p);
}
q->pHead = q->pTail = NULL;
q->num = 0;
return 0;
}
--------------------------------------------------------------------------------------------------
linkSqueue_main.c
--------------------------------------------------------------------------------------------------
#include "LinkSqueue.h"
int main()
{
LinkQueue queue;
LQ_init(&queue,10);
register int i = 1;
for(; i <= 10 ; i++)
{
LQ_push(&queue, i);
}
if( -1 == LQ_push(&queue,1024))
{
fprintf(stderr,"满队,入队失败!\n");
}
while(!LQ_isempty(&queue))
{
DATA data;
LQ_pop(&queue,&data);
printf("%4d",data);
}
printf("\n");
LQ_free(&queue);
return 0;
}