【数据结构】栈和队列OJ题


:本文所使用代码语言为C语言,栈和队列均为笔者用C语言实现,详情请看 栈和队列的C语言实现

本文所使用的栈和队列的结构

typedef char DataType;
typedef struct Stack
{
	DataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;
void StackInit(Stack* ps)//初始化栈
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void StackPush(Stack* ps, DataType data)//入栈
{
	assert(ps);
	if (ps->top == ps->capacity||ps->top==0)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		DataType* tmp = (DataType*)realloc(ps->a, sizeof(DataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	(ps->a)[ps->top] = data;
	ps->top++;
}

void StackPop(Stack* ps)//出栈
{
	assert(ps);
	assert(ps->top>0);
	ps->top--;
}

int StackSize(Stack* ps)//获取栈中有效元素的个数
{
	assert(ps);
	return ps->top;
}

DataType StackTop(Stack* ps)//获取栈顶元素
{
	assert(ps);
	return (ps->a)[ps->top - 1];
}

int StackEmpty(Stack* ps)//检测栈是否为空 如果为空就返回1,不为空就返回0
{
	assert(ps);
	return ps->top == 0;
}
void StackDestory(Stack* ps)//销毁栈
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

队列

typedef int DataType;

typedef struct QListNode
{
	DataType data;
	struct QListNode* next;
}Node;

typedef struct Queque
{
	Node* head;
	Node* tail;
	int size;
}Queue;

void QueueInit(Queue* p);//初始化
void QueuePush(Queue* p, DataType x);//队尾入队列
void QueuePop(Queue* p);//队头出数据
DataType QueueFront(Queue* p);//获取队列头部元素
DataType QueueBack(Queue* p);//获取队列尾部元素
int QuequeSize(Queue* p);//获取队列中有效元素的个数
bool QueueEmpty(Queue* p);//检测队列是否为空
void QueueDestroy(Queue* p);//销毁队列

void QueueInit(Queue* p)//初始化
{
	assert(p);
	p->head = NULL;
	p->tail = NULL;
	p->size = 0;
}

void QueuePush(Queue* p, DataType x)//队尾入队列
{
	assert(p);
	Node* newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (p->head == NULL)
	{
		p->head = newnode;
		p->tail = newnode;
	}
	else
	{
		p->tail->next = newnode;
		p->tail = newnode;
	}
	p->size++;
}

void QueuePop(Queue* p)//队头出队列
{
	assert(p);
	assert(p->head);//如果没有数据就出不了了
	Node* tmp = p->head;
	p->head = p->head->next;
	if (p->tail == tmp)
	{ 
		p->tail = p->tail->next;
	}
	free(tmp);
	p->size--;
}
DataType QueueFront(Queue* p)//获取队列头部元素
{
	assert(p && p->head);
	return p->head->data;
}
DataType QueueBack(Queue* p)//获取队列尾部元素
{
	assert(p && p->head);
	return p->tail->data;
}
int QuequeSize(Queue* p)//获取队列中有效元素的个数
{
	assert(p);
	return p->size;
}
bool QueueEmpty(Queue* p)//检测队列是否为空
{
	assert(p);
	return p->head == NULL;
}
void QueueDestroy(Queue* p)//销毁队列
{
	assert(p);
	while (p->head)
	{
		Node* tmp = p->head;
		p->head = p->head->next;
		free(tmp);
	}
	p->tail = NULL;
	p->head = NULL;
	p->size = 0;
}

括号匹配问题(有效的括号)

在这里插入图片描述
题目链接

解题思路
  如果是一个符合题意的字符串,那么当在字符串中遇到一个左括号时,在后续的遍历中,一定会有有一个相同类型的右括号与之对应。当多试几个样例后会发现,倘若是多个左括号在一起,那么最先配对成功的一定就是最后一个。依照这个思路,可以尝试用栈这个数据结构。
  所以,当我们在遍历字符串碰到左括号时,就将左括号进行压栈操作,每当碰到右括号时,就将左括号取出看是否与其对应,如此往复,直到字符串遍历完或者出现括号不对应的情况。


bool isValid(char * s){
    Stack st;
    StackInit(&st);
    while(*s)
    {
        if(*s=='('||*s=='['||*s=='{')//左括号就进栈
        {
            StackPush(&st,*s);
        }
        if(*s==')'||*s==']'||*s=='}')//碰过右括号就比较
        {
            if (StackEmpty(&st))//如果栈内为空
            {
                StackDestory(&st);
                return false;
            }
            char top=StackTop(&st);
            StackPop(&st);
            if((top=='('&&*s!=')')||(top=='{'&&*s!='}')||(top=='['&&*s!=']'))
            {
                return false;
            }
        }
        s++;
    }
    if (StackEmpty(&st))//如果栈内为空
    {
        StackDestory(&st);
        return true;
    }
    StackDestory(&st);
    return false;
}

用队列实现栈

在这里插入图片描述
思路
设置两个队列,一个用于导入数据,一个用于存储数据
例:

在这里插入图片描述

  当需要Pop的时候,就将存储数据的队列的前n-1个数据挪到另一个队列,在将最后一个数删掉(因为从栈的角度上,1是在“栈底”的元素,4是“栈顶”的元素)
在这里插入图片描述
  当再次往"栈"里插入数据的时候,就将插入到不为空的队列里
在这里插入图片描述

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)))//当q1不为空时
    {
        QueuePush(&(obj->q1),x);
    }
    else
    {
        QueuePush(&(obj->q2),x);
    }
}

int myStackPop(MyStack* obj) {
    Queue*empty=&(obj->q1);
    Queue*nonEmpty=&(obj->q2);
    if(!QueueEmpty(&(obj->q1)))//先确定好哪个为空,哪个不为空
    {
        nonEmpty=&(obj->q1);
        empty=&(obj->q2);
    }
    while(QuequeSize(nonEmpty)>1)//再将不为空的队列中的数往为空的队列中转移
    {
        QueuePush(empty,QueueFront(nonEmpty));
        QueuePop(nonEmpty);
    }
    int top=QueueFront(nonEmpty);
    QueuePop(nonEmpty);
    return top;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&(obj->q1)))
    {
        return QueueBack(&(obj->q1));
    }
    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,所以,我们还需要一个栈来放前面的两个元素
在这里插入图片描述

  此时3就成为了栈顶的数据,可以对其进行取出或者删除操作
  于是就有了这么一条思路
  准备两个栈,一个负责push(插入)数据,一个负责pop(删除)数据,当需要进行push操作时,就将数据往push栈中插入;若要进行pop操作时,先看pop栈有没有数据可供pop,如果有,就直接从pop栈中弹出数据,若没有,就先将push栈中的数据挪到pop栈中,在进行pop操作

typedef struct {
    Stack PushSt;
    Stack PopSt;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue*queue=(MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&(queue->PushSt));
    StackInit(&(queue->PopSt));
    return queue;
}

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

int myQueuePop(MyQueue* obj) {
    if(StackEmpty(&(obj->PopSt)))//如果PopSt栈中没有数据的话,就要先从PushSt中导入数据
    {
        while(!StackEmpty(&(obj->PushSt)))
        {
            StackPush(&(obj->PopSt),StackTop(&(obj->PushSt)));
            StackPop(&(obj->PushSt));
        }
    }
    int tmp=StackTop(&(obj->PopSt));
    StackPop(&(obj->PopSt));
    return tmp;
}

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&(obj->PopSt)))//如果PopSt栈中没有数据的话,就要先从PushSt中导入数据
    {
        while(!StackEmpty(&(obj->PushSt)))
        {
            StackPush(&(obj->PopSt),StackTop(&(obj->PushSt)));
            StackPop(&(obj->PushSt));
        }
    }
    return StackTop(&(obj->PopSt));
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&(obj->PopSt))&&StackEmpty(&(obj->PushSt));
}

void myQueueFree(MyQueue* obj) {
    StackDestory(&(obj->PopSt));
    StackDestory(&(obj->PushSt));
    free(obj);
}

设计循环队列

在这里插入图片描述
题目链接

思路
  循环队列的实现用不论是顺序表还是链表都可以,这里用顺序表来介绍思路
  由于题目中要我们实现的循环队列的长度是固定的,我们很容易想到,直接在动态申请大小为k个int大小的连续空间,由于是可循环的,它的逻辑图如下
在这里插入图片描述
实际情况如下
在这里插入图片描述
  每当往队列里插入数据时,队列尾就往后一格,当删除数据的时候,队列头就往前一格,队列头和队列尾之间的位置就是有效元素
在这里插入图片描述
  当一直插入数据直到队列满时
在这里插入图片描述
  此时,队头和队尾指向同一个位置,但是当队列为空时,队头和队尾也是指向同一个位置,不好区分。
  于是,我们在申请空间时,申请的空间要比规定长度大1,这多出来的空间就可以用来做区分:
  当队列的头和尾指向一起时,就说明此时的队列为空,倘若队列尾的下一个元素被队列头指着,说明此时,队列已经满了
在这里插入图片描述

typedef struct {
    int*arr;
    int front;
    int rear;
    int k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*queue=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    queue->arr=(int*)malloc(sizeof(int)*(k+1));
    queue->front=0;
    queue->rear=0;
    queue->k=k;
    return queue;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if((obj->rear+1)%(obj->k+1)==obj->front)//如果队列满了
    {
        return false;
    }
    obj->arr[obj->rear]=value;
    obj->rear++;
    if(obj->rear>obj->k)
    {
        obj->rear=(obj->rear)%(obj->k+1);
    }
    printf("%d %d\n",obj->front,obj->rear);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(obj->front==obj->rear)//如果队列为空
    {
        return false;
    }
    obj->front++;
    if(obj->front>obj->k)
    {
        obj->front=(obj->front)%(obj->k+1);
    }
    printf("%d %d\n",obj->front,obj->rear);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->front==obj->rear)//如果队列为空
    {
        return -1;
    }
    printf("%d %d\n",obj->front,obj->rear);
    return obj->arr[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(obj->front==obj->rear)//如果队列为空
    {
        return -1;
    }
    if(obj->rear==0)
    {
        return obj->arr[obj->k];
    }
    printf("%d %d\n",obj->front,obj->rear);
    return obj->arr[obj->rear-1];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->front==obj->rear)//如果队列为空
    {
        return true;
    }
    printf("%d %d\n",obj->front,obj->rear);
    return false;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if((obj->rear+1)%(obj->k+1)==obj->front)//如果队列满了
    {
        return true;
    }
    printf("%d %d\n",obj->front,obj->rear);
    return false;
}

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

用链表结构实现

typedef struct QueueNode
{
    int data;
    struct QueueNode*next;
}QueueNode;

typedef struct {
    QueueNode*tail;
    QueueNode*front;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
    QueueNode*node=(QueueNode*)malloc(sizeof(QueueNode));//多出来的那个结点
    MyCircularQueue*queue=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    node->next=NULL;
    QueueNode*tmp=node;
    for(int i=1;i<=k;i++)
    {
        QueueNode*newnode=(QueueNode*)malloc(sizeof(QueueNode));
        newnode->next=NULL;
        tmp->next=newnode;
        tmp=tmp->next;
    }
    tmp->next=node;//创建了一个循环链表
    queue->tail=node;
    queue->front=node;
    return queue;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->tail->next==obj->front)
    {
        return true;
    }
    return false;
}

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

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//如果是满的话
    {
        return false;
    }
    obj->tail->data=value;
    obj->tail=obj->tail->next;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(obj->front==obj->tail)//没有元素可以删了
    {
        return false;
    }
    obj->front=obj->front->next;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->front->data;
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    QueueNode*cur=obj->front;
    while(cur->next!=obj->tail)
    {
        cur=cur->next;
    }
    return cur->data;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    QueueNode*cur=obj->front;
    QueueNode*Next=cur->next;
    while(1)
    {
        if(cur==obj->tail)
        {
            free(cur);
            obj->front=NULL;
            obj->tail=NULL;
            break;
        }
        free(cur);
        cur=Next;
        Next=Next->next;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值