目录
1.栈
1.1栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
进行数据插入和删除操作的一端
称为栈顶,另一端称为栈底。
栈中的数据元素遵守后进先出
LIFO
(
Last In First Out)的原则。
出栈是相对的,相对于同时在栈中的元素
压栈:栈的插入操作叫做进栈
/
压栈
/
入栈,
入数据在栈顶
。
出栈:栈的删除操作叫做出栈。
出数据也在栈顶
。
1.2栈的实现
栈的实现一般可以使用
数组或者链表实现
,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的 代价比较小。
![](https://i-blog.csdnimg.cn/blog_migrate/86b43b9c7d6fd7958fd7d13d3c49c4f7.png)
stack.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int STDatatype;
typedef struct Stack
{
STDatatype* a;//用指针指向开辟空间的起始地址//用数组来存放数据,数组名就是首元素的地址
//存放相同类型数据就用素组,不同多种类型用结构体,类似顺序表
int capacity;
int top; // 初始为0,表示栈顶位置下一个位置下标
}ST;
//注意栈的一个特点,都是对栈顶元素进行修改
//为了方便我们把数组的尾定义为栈顶
//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestroy(ST* ps);
//入栈
void StackPush(ST* ps, STDatatype x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDatatype StackTop(ST* ps);
//布尔关键字bool,只需要两种状态就可以用
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
stack.c
注意出栈(只是把栈顶元素下标去掉)可以和找到栈顶元素进行搭配
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void StackInit(ST* ps)
{
assert(ps);
ps->a == NULL;
ps->capacity == 0;
ps->top == 0;
//另外一种写法
//注释,ctrl+k+c
/*解除注释,ctrl+k+u*/
/*ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
if (ps->a == NULL)
{
perror("malloc fail");
exit(-1);
}
ps->top = 0;
ps->capacity = 4;*/
}
void StackDestroy(ST* ps)
{
assert(ps);
//free之后别忘记置空
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
//入栈
void StackPush(ST* ps, STDatatype x)
{
assert(ps);
//首先要检查是否还有空间
if (ps->top == ps->capacity)
{
STDatatype* tmp = (STDatatype*)realloc(ps->a,ps->capacity*sizeof(STDatatype)*4);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
//出栈
void StackPop(ST* ps)
{
assert(ps);//指针不为空指针
assert(!StackEmpty(ps));//栈也不为空
ps->top--;//删除只需减去栈顶top
}
//找到栈顶元素
STDatatype StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));//一种意思
return ps->a[ps->top - 1];
}
//布尔关键字bool,只需要两种状态就可以用
//空为真
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->a[ps->top] == 0;
}
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void TestStack1()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
printf("size:%d\n", StackSize(&st)); // 不关心底层实现
//printf("size:%d\n", st.top); // 关心
printf("size:%d\n", st.top + 1); // 关心
StackPop(&st);
StackPop(&st);
StackPop(&st);
StackPop(&st);
StackPop(&st);
//StackPop(&st);
//printf("%d\n", StackTop(&st));
StackDestroy(&st);
}
int main()
{
TestStack1();
return 0;
}
2.队列
2.1队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为
队尾
出队列:进行删除操作的一端称为
队头
![](https://i-blog.csdnimg.cn/blog_migrate/6aaed2bcccead66d6d79f20780d55d24.png)
2.2队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。
![](https://i-blog.csdnimg.cn/blog_migrate/60d20c9b0d45b66a601f27753946621e.png)
Queue.h
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
//typedef 原来的 现在的
//使用的是现在的
//作用为一种数据类型定义一个新名字
//用链表来表示队列
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
// 控制队列用头和尾指针,这是队列的结构
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType x);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
Queue.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->head = NULL;
q->tail = NULL;
q->size = 0;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType x)
{
assert(q);
QNode* node = (QNode*)malloc(sizeof(QNode));
//用malloc开辟空间一定不要忘记判断
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
node->data = x;
node->next = NULL;
if (q->tail == NULL)//如果带头就不需要判断直接链接
{
q->head = q->tail = node;
}
else
{
q->tail->next = node;//链接
q->tail = node;//后移
}
q->size++;
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
//考虑特殊情况只有一个节点
if (q->head->next == NULL)
{
q->head = q->tail = NULL;
}
else
{
Queue* del = q->head;
q->head = q->head->next;
free(del);//通常free之后要置空,这里不需要置空是因为del是一个局部变量出作用域会销毁
}
q->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);//q不能为空指针
assert(!QueueEmpty(q));//这个队列要不为空
return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);//q不能为空指针
assert(!QueueEmpty(q));//这个队列要不为空
return q->tail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);//q不能为空指针
//assert(!QueueEmpty(q));//这个队列要不为空
return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
assert(q);
return q->head == NULL && q->tail == NULL;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
QNode* cur = q->head;
while (cur)
{
Queue* del = q->head;
cur = cur->next;
free(del);
}
q->head = q->tail = NULL;
q->size = 0;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"
void TestQueue()
{
//Queue q1;
//Queue q2;
//QueueInit(&q1);
//QueueInit(&q2);
//QueueDestroy(&q1);
//QueueDestroy(&q2);
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
printf("%d ", QueueFront(&q));
QueuePop(&q);
QueuePush(&q, 3);
QueuePush(&q, 4);
printf("%d\n", QueueSize(&q));
printf("%d\n", QueueEmpty(&q));
printf("%d\n", QueueFront(&q));
printf("%d\n", QueueBack(&q));
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
printf("%d\n", QueueSize(&q));
printf("%d\n", QueueEmpty(&q));
//printf("%d\n", QueueFront(&q));
//printf("%d\n", QueueBack(&q));
QueueDestroy(&q);
}
int main()
{
TestQueue();
return 0;
}