1.栈
目录
1.1什么是栈
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
eg:入栈时1 2 3 4 出栈时4 3 2 1
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。所以我们选择数组栈。
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;//是不是和顺序表一毛一样
void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)//进栈
{
assert(ps);
if (ps->top == ps->capacity)//扩容
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //初始化总体的容量
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
//存储一个数据的小空间
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);//异常退出
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++; //就相当于顺序表那一块的size
}
STDataType STTop(ST* ps)//获取栈顶元素
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
//top是指向栈顶元素的下一个元素
}
void STPop(ST* ps)//出栈
{
assert(ps);
//防止top为0
assert(ps->top>0);//如果top=0,再减就成负数了
ps->top--;
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
2.队列
2.1什么是队列
队列:就是一个简单的单向链表。它遵循FIFO(First In First Out)原则。
这个FIFO(First In First Out)原则 eg:进栈时1 2 3 4,出栈时1 2 3 4.
注意:在入队列时进行插入操作的一端称为队尾 ,在出队列时进行删除操作的一端称为队头。
并且顺序不能改变,只能头删尾增。
2.2队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdbool.h>
#include<stdio.h>
#include<stdlib.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;
}Que;
void QueueInit(Que* pq);
void QueueDestroy(Que* pq);
void QueuePush(Que* pq, QDataType x);
void QueuePop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* pq);
void QueueInit(Que* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Que* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Que* pq, QDataType x)
{
assert(pq);
//开辟空间
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
//处理数据
newnode->data = x;
newnode->next = NULL;
//处理tail
if (pq->tail == NULL)//刚开始
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;//链接newnode,更新tail
}
//处理size
pq->size++;
}
void QueuePop(Que* pq)
{
assert(pq);
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}//只有一个节点,得考虑tail
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;//更新head
}
//处理size
pq->size--;
}
QDataType QueueFront(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Que* pq)
{
assert(pq);
return pq->head == NULL;
}
int QueueSize(Que* pq)
{
assert(pq);
return pq->size;
}
3.经典例题
3.1用队列实现栈
链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
队列的特点是:先进先出,栈的特点是后进先出。
思路图:
缺点:把数据导来导去,容易搞混。
代码:
typedef struct {
Que q1;
Que q2;
} MyStack;
MyStack* myStackCreate() {
MyStack*obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))//如果q1不为空则入栈
{
QueuePush(&obj->q1,x);
}
else//如果q2不为空则入栈
{
QueuePush(&obj->q1,x);
}
}
int myStackPop(MyStack* obj) {
Que*empty=&obj->q1;//假设q1为空
Que*Noempty=&obj->q2;//假设q2为空
if(!QueueEmpty(&obj->q1))//假设q1不为空
{
Noempty=&obj->q1;
empty=&obj->q2;
}//找到了空的队列
while(QueueSize(Noempty)>1)
{
QueuePush(empty,QueueFront(Noempty));
QueuePop(Noempty);
}
int top=QueueFront(Noempty);
QueuePop(Noempty);
return top;
}
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);
}
3.2用栈实现队列
和上面的思路类似,但是这个不用把数据导来导去,进数据只在push栈里,出数据只在pop栈里。
思路图:
代码:
typedef struct {
ST push;
ST pop;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue *)malloc(sizeof(MyQueue));
InitStack(&obj->push);
InitStack(&obj->pop);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
PushStack(&obj->push, x); //入栈操作均放入push
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->push) && StackEmpty(&obj->pop);
}
int myQueuePop(MyQueue* obj) {
int peek = myQueuePeek(obj);
PopStack(&obj->pop);
return peek;
}
int myQueuePeek(MyQueue* obj) {
if(StackEmpty(&obj->pop)) //如果pop栈为空,则进行一个倒栈操作
{
while(!StackEmpty(&obj->push))
{
PushStack(&obj->pop, StackTop(&obj->push));
PopStack(&obj->push);
}
}
return StackTop(&obj->pop);
}
void myQueueFree(MyQueue* obj) {
DestroyStack(&obj->push);
DestroyStack(&obj->pop);
free(obj);
}
喜欢的话点个赞,感谢感谢 !!!!