3.栈和队列

遵循LIFO原则
数据插入和删除的一端称为栈顶

栈的实现

数组,双向带头循环链表,单链表均可

image-20220210203249342

头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量,方便增容
};
typedef struct Stack Stack;

void StackInit(Stack* pst);
void StackDestroy(Stack* pst);
//性质决定了只能在栈顶出入数据
void StackPush(Stack* pst, STDataType x);
void StackPop(Stack* pst);
STDataType StackTop(Stack* pst);
bool StackEmpty(Stack* pst);
int StackSize(Stack* pst);

初始化和销毁

void StackInit(Stack* pst)
{
	assert(pst);
	//初始时给一定空间大小方便增容
	pst->a = (STDataType*)malloc(sizeof(STDataType)*4);
	pst->top = 0;
	pst->capacity = 4;
}
void StackDestroy(Stack* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->capacity = pst->top = 0;
}

Push&Pop

//性质决定了只能在栈顶出入数据
void StackPush(Stack* pst, STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		STDataType* tmp = realloc(pst->a, sizeof(STDataType) * pst->capacity * 2);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);//结束整个程序,return是结束当前函数
		}
		pst->a = tmp;
		pst->capacity *= 2;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void StackPop(Stack* pst)
{
	assert(pst);
	//非空才能删除
	assert(!StackEmpty(pst));
	pst->top--;//无需取抹除原来空间的元素,只要访问不到就行
}

是否为空

bool StackEmpty(Stack* pst)
{
	assert(pst);
	return pst->top == 0;
}

求大小

int StackSize(Stack* pst)
{
	assert(pst);
	return pst->top;//top恰好就是size大小
}

取栈顶元素

//取栈顶元素
STDataType StackTop(Stack* pst)
{
	assert(pst);
	//非空才能取值
	assert(!StackEmpty(pst));
	return pst->a[pst->top-1];
}

Test文件

void Test()
{
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);

	//栈不支持print接口,因为只能后进先出
	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}

	StackDestroy(&st);
}
int main()
{
	Test();
	return 0;
}

队列

FIFO先进先出

image-20220210221819040

队列的实现

用单链表更合适

头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}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);

初始化&销毁

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

Push&Pop

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//如果没有节点
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}
void QueuePop(Queue* pq)
{
	//对头出数据,即头删
	assert(pq);
	assert(!QueueEmpty(pq));//队列为空
	if (pq->head->next == NULL)
	{
		//只有一个节点的情况
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QueueNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

取值

//取队头数据
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);
	int size = 0;
	QueueNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

Test

void TestQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	QueuePush(&q, 5);

	while (!QueueEmpty(&q))
	{
		//只能出队头
		printf("%d ",QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
	QueueDestroy(&q);
}

练习

20. 有效的括号

bool isValid(char * s)
{
    Stack st;
    StackInit(&st);
    while(*s)
    {
        //左括号入栈
        //右括号找最近的左括号匹配
        if(*s == '[' || *s == '(' || *s == '{')
        {
            StackPush(&st,*s);
            s++;
        }
        else
        {
            //为空,说明没有前括号
            if(StackEmpty(&st))
            {
                //return之前一定要destroy,防止内存泄露
                //编译器自身检查不出来内存泄露
                StackDestroy(&st);
                return false;
            }
            char top = StackTop(&st);

            if((top =='[' && *s != ']')//不匹配
            ||  (top =='(' && *s != ')')
            ||  (top =='{' && *s != '}')
            )
            {
                StackDestroy(&st);
                return false;
            }
            else
            {
                //匹配的情况
                StackPop(&st);
                s++;
            }
        }
    }
    //如果只有左括号,stack不为空应该返回false
    bool ret = StackEmpty(&st);
    StackDestroy(&st);
    return ret;
}

一定要防止内存泄露

225. 用队列实现栈

image-20220211113254747

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    //->优先级更高
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst;
}

void myStackPush(MyStack* obj, int x) {
    //往不为空的队列入数据
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
    else
    {
        QueuePush(&obj->q2, x);
    }
}

int myStackPop(MyStack* obj) {
    Queue* pEmpty = &obj->q1;
    Queue* pNonEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        pEmpty = &obj->q2;
        pNonEmpty = &obj->q1;
    }
    while(QueueSize(pNonEmpty)>1)
    {
        QueuePush(pEmpty,QueueFront(pNonEmpty));
        //插入到空队列后要pop掉
        QueuePop(pNonEmpty);
    }
    int front = QueueFront(pNonEmpty);
    QueuePop(pNonEmpty);
    return front;
}

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);
    //因为是值传递,不改变实参的值,置空也没用,需要在调用myStackFree接口之后手动置空
    //obj = NULL;
}

232. 用栈实现队列

image-20220211131219813

typedef struct {
    Stack pushST;
    Stack popST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&q->pushST);
    StackInit(&q->popST);
    return q;
}

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushST, x);
}

//remove the front element
int myQueuePop(MyQueue* obj) {
    int top = myQueuePeek(obj);
    StackPop(&obj->popST);
    return top;
}

//Get the front element
int myQueuePeek(MyQueue* obj) {
    //先判断popST是否为空
    if(StackEmpty(&obj->popST))
    {
        //from pushST to popST
        while(!StackEmpty(&obj->pushST))
        {
            StackPush(&obj->popST, StackTop(&obj->pushST));
            //pop the element of pushST
            StackPop(&obj->pushST);
        }
    }
    //popST 不为空 直接Top the element
    return StackTop(&obj->popST);
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}

void myQueueFree(MyQueue* obj) {
    //要销毁stack先
    StackDestroy(&obj->pushST);
    StackDestroy(&obj->popST);
    free(obj);
    //还需要在接口外面将obj置为NULL
}

622. 设计循环队列

  • 如果front和tail指向同一个位置,那么空满条件都相同
  • 解决:永远空一个位置 tail-> next== front 表示满 头尾相等表示空

image-20220211134927472

typedef struct {
    int* a;//数组
    int k;//队列最多能存储的元素
    int front;
    int tail;//尾(队尾数据的下一个)
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    int tailNext = obj->tail+1;
    //小心越界
    if(tailNext == obj->k+1)
    {
        tailNext = 0;
    }
    return tailNext == obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int)*(k+1));//k+1个空间
    obj->front = 0;
    obj->tail = 0;
    obj->k = k;
    return obj;
}


//入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{   
    //判断是否满
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    else
    {
        obj->a[obj->tail] = value;
        obj->tail++;
        //超出范围回到0
        if(obj->tail == obj->k+1)
        {
            obj->tail = 0;
        }
        //取模也行,但尽量不要用% CPU只有加法器
        return true;
    }
}

//删数据    
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //判断是否空
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        obj->front++;
        //超出范围回到0
        if(obj->front == obj->k+1)
        {
            obj->front = 0;
        }
        //取模也行,但尽量不要用% CPU只有加法器
        return true;
    }
}

//get front element
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->a[obj->front];
    }
}
//get rear element
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        int tailPrev = obj->tail-1;
        if(tailPrev == -1)
        {
            tailPrev = obj->k;
        }
        return obj->a[tailPrev];
    }
}



void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

注意复用函数时要注意是否有声明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值