目录
一.栈的表示和实现
1.栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵循后进先出LIFO(Last in First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶
2.栈的实现
从上面我们也可以看出来,栈的实现一般可以使用数组或者链表实现,相对而言,其实数组的结构实现更优一些,因为数组在尾上插入数据的代价比较小
二、栈的实现
1.栈的声明和定义
根据我们上面的分析,我们决定使用顺序表来实现栈。所以它的声明如下
typedef int STDateType;
typedef struct Stack
{
STDateType* a;
int top;
int capacity;
}Stack;
2.栈的初始化
它的声明如下
//栈的初始化
void StackInit(Stack* ps);
它的函数实现也很简单
//栈的初始化
void StackInit(Stack* ps)
{
assert(ps);
ps->a = (STDateType*)malloc(4 * sizeof(STDateType));
if (ps->a == NULL)
{
printf("malloc is fail\n");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
注意这里的top可以为0也可以为-1
这两种其实也是有区别的,
如果top初始化为0的化,那就意味着top指向栈顶元素的下一个
如果top初始化欸-1的话,那么意味着top指向栈顶元素
3.栈的销毁
创建好那么必要要有销毁
销毁的声明为
//栈的销毁
void StackDestory(Stack* ps);
实现为
//栈的销毁
void StackDestory(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
4.入栈
这个也非常简单,函数声明为
//入栈
void StackPush(Stack* ps, STDateType x);
实现为
//入栈
void StackPush(Stack* ps, STDateType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
//扩容
STDateType* tmp = (STDateType*)realloc(ps->a, sizeof(STDateType) * 2 * ps->capacity);
if (tmp == NULL)
{
printf("realloc is fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
5.出栈
函数声明为
//出栈
void StackPop(Stack* ps);
函数实现为
//出栈
void StackPop(Stack* ps)
{
assert(ps);
//栈为空了,还想要继续删除直接报错
assert(ps->top > 0);
ps->top--;
}
6.返回栈顶元素
这是函数声明
//取出栈顶元素
STDateType StackTop(Stack* ps);
这是函数实现
//取出栈顶元素
STDateType StackTop(Stack* ps)
{
assert(ps);
//栈为空,还继续调用的话直接报错
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
7.返回栈的元素个数
这是函数声明
//栈的元素个数
int StackSize(Stack* ps);
这是函数实现
//栈的元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
8.栈是否为空
这是函数声明
//栈是否为空
bool StackEmpty(Stack* ps);
这是函数实现
//栈是否为空
bool StackEmpty(Stack* ps)
{
assert(ps);
return (ps->top == 0);
}
9.测试
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
int main()
{
Stack s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
printf("%d ", StackTop(&s));
StackPop(&s);
printf("%d ", StackTop(&s));
StackPop(&s);
StackPush(&s, 4);
StackPush(&s, 5);
while (!StackEmpty(&s))
{
printf("%d ", StackTop(&s));
StackPop(&s);
}
StackDestory(&s);
}
运行结果为
三、栈的完整代码
Test.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
int main()
{
Stack s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
printf("%d ", StackTop(&s));
StackPop(&s);
printf("%d ", StackTop(&s));
StackPop(&s);
StackPush(&s, 4);
StackPush(&s, 5);
while (!StackEmpty(&s))
{
printf("%d ", StackTop(&s));
StackPop(&s);
}
StackDestory(&s);
}
Stack.h文件
#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
typedef int STDateType;
typedef struct Stack
{
STDateType* a;
int top;
int capacity;
}Stack;
//栈的初始化
void StackInit(Stack* ps);
//栈的销毁
void StackDestory(Stack* ps);
//入栈
void StackPush(Stack* ps, STDateType x);
//出栈
void StackPop(Stack* ps);
//取出栈顶元素
STDateType StackTop(Stack* ps);
//栈的元素个数
int StackSize(Stack* ps);
//栈是否为空
bool StackEmpty(Stack* ps);
Stack.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
//栈的初始化
void StackInit(Stack* ps)
{
assert(ps);
ps->a = (STDateType*)malloc(4 * sizeof(STDateType));
if (ps->a == NULL)
{
printf("malloc is fail\n");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
//栈的销毁
void StackDestory(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
//入栈
void StackPush(Stack* ps, STDateType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
//扩容
STDateType* tmp = (STDateType*)realloc(ps->a, sizeof(STDateType) * 2 * ps->capacity);
if (tmp == NULL)
{
printf("realloc is fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
//出栈
void StackPop(Stack* ps)
{
assert(ps);
//栈为空了,还想要继续删除直接报错
assert(ps->top > 0);
ps->top--;
}
//取出栈顶元素
STDateType StackTop(Stack* ps)
{
assert(ps);
//栈为空,还继续调用的话直接报错
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
//栈的元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
//栈是否为空
bool StackEmpty(Stack* ps)
{
assert(ps);
return (ps->top == 0);
}
四、队列的表示和实现
1.队列的概念和结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First in First Out)入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
2.队列的实现
队列也可以数组和链表的结构实现,但使用链表的结构更优一些,因为如果使用数组的结构,出队列在数组的头上出数据,效率会比较低.
五、队列的实现
1.队列的声明和定义
我们想要使用链表的结构来实现队列,但是由于单链表的尾插过于麻烦,不妨我们直接声明头节点和尾结点来控制队列
typedef int QDateType;
typedef struct QueueNode
{
struct QueueNode* next;
QDateType date;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
如上所示,我们先定义了一个队列结点的结构体,里面包含了指向下一个结点的指针和一个队列的数据。然后我们定义了一个队列结构体,我们主要是使用队列这个结构体,它里面有头结点和尾结点,有头有尾刚好确定一个队列。
2.队列的初始化
接下来让我们先来实现一下队列的初始化
函数声明为
//队列初始化
void QueueInit(Queue* pq);
实现为
//队列的初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
其实对这个实现,建议与前面的一些LeetCode题目和单链表的实现进行对比,我们可以看出来这里的妙处。
3.队列的销毁
有始有终,我们来实现一下队列的销毁
//队列的销毁
void QueueDestory(Queue* pq);
函数实现为
//队列的销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
4.队列的插入
函数声明为
//队列的插入
void QueuePush(Queue* pq, QDateType x);
函数实现为
//队列的插入
void QueuePush(Queue* pq, QDateType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("malloc is fail\n");
exit(-1);
}
//对新节点进行初始化
newnode->date = x;
newnode->next = NULL;
//对新结点进行连接
if (pq->head == NULL)
{
//头结点是空的,也就是第一个数据的插入
pq->head = pq->tail = newnode;
}
else
{
//非第一个数据的插入
pq->tail->next = newnode;
pq->tail = newnode;
}
}
5.队列的删除
函数声明为
//队列的删除
void QueuePop(Queue* pq);
函数实现为
//队列的删除
void QueuePop(Queue* pq)
{
assert(pq);
//确保队列不是空的队列
assert(pq->head);
//如果只有一个结点,防止tail形成野指针
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
//不是只有一个结点
else
{
//保存第二个队列结点
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
6.队列的判空
函数声明
//判断队列是否为空
bool QueueEmpty(Queue* pq);
函数实现
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
7.取出队头的数据
函数声明
//取出队头的数据
QDateType QueueFront(Queue* pq);
函数实现
//取出队头的数据
QDateType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->date;
}
8.取出队尾的数据
函数声明
//取出队尾的数据
QDateType QueueBack(Queue* pq);
函数实现
//取出队尾的数据
QDateType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->tail->date;
}
9.队列数据的个数
函数声明
//取出数据的个数
int QueueSize(Queue* pq);
函数实现
//取出数据的个数
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
cur = cur->next;
size++;
}
return size;
}
10.测试
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
QueueDestory(&q);
}
int main()
{
//TestStack();
TestQueue();
}
运行结果为
六、队列完整代码
Test.c
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
QueueDestory(&q);
}
int main()
{
//TestStack();
TestQueue();
}
Queue.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDateType;
typedef struct QueueNode
{
struct QueueNode* next;
QDateType date;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
//队列初始化
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestory(Queue* pq);
//队列的插入
void QueuePush(Queue* pq, QDateType x);
//队列的删除
void QueuePop(Queue* pq);
//取出队头的数据
QDateType QueueFront(Queue* pq);
//取出队尾的数据
QDateType QueueBack(Queue* pq);
//取出数据的个数
int QueueSize(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
Queue.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
//队列的初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
//队列的销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
//队列的插入
void QueuePush(Queue* pq, QDateType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("malloc is fail\n");
exit(-1);
}
//对新节点进行初始化
newnode->date = x;
newnode->next = NULL;
//对新结点进行连接
if (pq->head == NULL)
{
//头结点是空的,也就是第一个数据的插入
pq->head = pq->tail = newnode;
}
else
{
//非第一个数据的插入
pq->tail->next = newnode;
pq->tail = newnode;
}
}
//队列的删除
void QueuePop(Queue* pq)
{
assert(pq);
//确保队列不是空的队列
assert(pq->head);
//如果只有一个结点,防止tail形成野指针
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
//不是只有一个结点
else
{
//保存第二个队列结点
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
//取出队头的数据
QDateType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->date;
}
//取出队尾的数据
QDateType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->tail->date;
}
//取出数据的个数
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
cur = cur->next;
size++;
}
return size;
}
总结
本节实现了栈和队列的实现,难度不大,希望大家都能学会
如果对你有帮助,不要忘记点赞加收藏哦!!!
想获得更多优质的内容,一定要记得关注我哦!!!