一. 栈
1. 什么是栈
一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端
称为栈顶,另一端称为栈底。
栈中的数据元素遵守
后进先出LIFO
(
Last In First Out
)的原则
![](https://i-blog.csdnimg.cn/blog_migrate/0338f5d496ccccc44d620f57e50d493f.png)
2. 代码模拟栈
2.1 stack.h 和 stack.c
//---------------------------stack.h-------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int capacity;
int top;
}ST;
void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDataType x);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
//---------------------------stack.c-------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
static void Check_Capacity(ST* ps)
{
assert(ps);
if (ps->capacity == ps->top)
{
int newncapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newncapacity);
if (NULL == tmp)
{
printf("realloc fail\n");
exit(-1);
}
ps->capacity = newncapacity;
ps->a = tmp;
//printf("realloc success\n");
}
}
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)
{
assert(ps);
Check_Capacity(ps);
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
2.2 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void stack_test1()
{
ST stack;
StackInit(&stack);
StackPush(&stack, 1);
StackPush(&stack, 2);
StackPush(&stack, 3);
StackPush(&stack, 4);
StackPush(&stack, 5);
StackPush(&stack, 6);
StackPush(&stack, 7);
StackPush(&stack, 8);
//StackPush(&stack, 9);
while (!StackEmpty(&stack))
{
printf("%d ", StackTop(&stack));
StackPop(&stack);
}
printf("\nsize = %d", stack.top);
printf("\ncapacity = %d", stack.capacity);
}
int main()
{
stack_test1();
return 0;
}
二 . 队列
1.什么是队列
队列:只允许在
一端进行插入数据操作
,
在另一端进行删除数据操作的特殊线性表
,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为
队头
![](https://i-blog.csdnimg.cn/blog_migrate/bc1806e5fc34756b2a8e41d406ac7e6a.png)
2. 代码模拟 队列
2.1 queue.h 和 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq,QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
//-------------------test.c----------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"
Qtest1()
{
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");
}
int main()
{
Qtest1();
return 0;
}
2.2 queue.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(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, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (NULL == newnode)
{
printf("malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (NULL == pq->tail)
{
pq->head = pq->tail = newnode;
pq->size++;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
pq->size++;
}
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{//1. 只有一个结点
free(pq->head);
pq->head = pq->tail = NULL;
pq->size--;
}
else
{//2. 多个结点
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
pq->size--;
}
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
三. 栈和队列相关题目【力扣】
1. 用队列实现栈 —— 栈 | 后进先出
队列实现栈的基本思想就是,用 2 个队列来实现栈,当第一次入栈时,从队列 1 中入队,出栈时,需要把队列 1 中的 n - 1个数据倒入到队列 2 中,然后将队列 1 中仅剩的最后一个数据出掉,这个就是出栈动作,当要在继续入栈时,需要入到有元素(队列 2)的栈,然后再次需要出栈时,以此往复,此过程中,始终有一个队列为空,入栈只入非空的队列。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
int size;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->size = 0;
q->_front = q->_rear = NULL;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* tmp = (QNode*)malloc(sizeof(QNode));
if (NULL == tmp)
{
perror("Push mfail");
exit(-1);
}
tmp->_data = data;
tmp->_next = NULL;
if (q->_rear == NULL)
{
q->_front = q->_rear = tmp;
}
else
{
q->_rear->_next = tmp;
q->_rear = tmp;
}
q->size++;
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
if(q->_front->_next == NULL)
{
free(q->_front);
q->_front = q->_rear = NULL;
}
else
{
QNode* hnext = q->_front->_next;
free(q->_front);
q->_front = hnext;
}
q->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
return q->_front->_data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
return q->_rear->_data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q)
{
assert(q);
return q->_front == NULL;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
//assert(!QueueEmpty(q));
QNode* cur = q->_front;
while (cur)
{
QNode* next = cur->_next;
free(cur);
cur = next;
}
q->_front = q->_rear = NULL;
q->size = 0;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack *st = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1, x);
}
else
{
QueuePush(&obj->q2, x);
}
}
int myStackPop(MyStack* obj) {
Queue* Nempty = &obj->q1;
Queue* Empty = &obj->q2;
if(QueueEmpty(&obj->q1))//判定非空队列
{
Nempty = &obj->q2;
Empty = &obj->q1;
}
while(QueueSize(Nempty) > 1)
{
QueuePush(Empty, QueueFront(Nempty));
QueuePop(Nempty);
}
int ret = QueueFront(Nempty);
QueuePop(Nempty);
return ret;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
2.用栈实现队列 —— 队列 | 后进后出
用栈实现队列的基本实现,用 2 个栈来实现队列,一个栈负责进队列,另一个栈负责出队列,当进元素时push栈负责接收元素,当需要pop元素时,则直接将pop栈中的元素依次pop出队列,当pop栈没有元素时,需要先将push栈的所有元素倒入到pop栈时。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->_a = NULL;
ps->_capacity = ps->_top = 0;//top是0,top指向的是栈顶元素的下一个位置。
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
if (ps->_capacity == ps->_top)
{
int newcapacity = ps->_capacity == 0 ? 2 : ps->_capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);
if (NULL == tmp)
{
perror("realloc fail");
exit(-1);
}
ps->_a = tmp;
ps->_capacity = newcapacity;
}
ps->_a[(ps->_top)++] = data;
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->_top > 0);//为空不能删了
--(ps->_top);
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
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;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_capacity = ps->_top = 0;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------/
typedef struct {
Stack st1;//入
Stack st2;//出
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* tmp = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&tmp->st1);
StackInit(&tmp->st2);
return tmp;
}
void myQueuePush(MyQueue* obj, int x) {
assert(obj);
StackPush(&obj->st1,x);
}
int myQueuePop(MyQueue* obj) {
assert(obj);
if(!StackEmpty(&obj->st2))//负责出的栈有数据就直接出
{
int ret = StackTop(&obj->st2);
StackPop(&obj->st2);
return ret;
}
else //没数据就要先把队列1的全部倒进来
{
while(StackSize(&obj->st1) > 0)
{
StackPush(&obj->st2,StackTop(&obj->st1));
StackPop(&obj->st1);
}
int ret = StackTop(&obj->st2);
StackPop(&obj->st2);
return ret;
}
}
int myQueuePeek(MyQueue* obj) {
assert(obj);
if(!StackEmpty(&obj->st2))//负责出的栈有数据就直接出
{
int ret = StackTop(&obj->st2);
return ret;
}
else //没数据就要先把队列1的全部倒进来
{
while(StackSize(&obj->st1) > 0)
{
StackPush(&obj->st2,StackTop(&obj->st1));
StackPop(&obj->st1);
}
int ret = StackTop(&obj->st2);
return ret;
}
}
bool myQueueEmpty(MyQueue* obj) {
assert(obj);
return StackEmpty(&obj->st1) && StackEmpty(&obj->st2);
}
void myQueueFree(MyQueue* obj) {
assert(obj);
StackDestroy(&obj->st1);
StackDestroy(&obj->st2);
free(obj);
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/
3. 设计循环队列 —— 数组实现
这里直接上图解和代码
typedef struct {
int front;
int tail;
int size;
int *arr;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if(NULL == obj)
{
perror("Cir mfail");
exit(-1);
}
int* tmp = (int*)malloc(sizeof(int) * (k + 1));
if(NULL == tmp)
{
perror("Cir mfail");
exit(-1);
}
obj->arr = tmp;
obj->front = obj->tail = 0;
obj->size = k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->tail + 1) %(obj->size + 1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->arr[obj->tail] = value;
obj->tail++;
obj->tail %=(obj->size + 1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front %=(obj->size + 1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->arr[(obj->tail + obj->size)%(obj->size + 1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
obj->front = obj->tail = obj->size = 0;
free(obj);
}