(C语言)数据结构之栈和队列面试题

题目1.括号匹配问题

题目链接

思路:
判断括号的有效性可以使用栈这一数据结构来解决。
我们遍历给定的字符串s。当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串s 无效,返回False。在上述的基础之上,在遍历结束后,如果栈中没有左括号,说明我们将字符串 s中的所有左括号闭合,返回True,否则返回 False。

实现代码:

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;
}ST;

void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps, STDataType x);
void StackPop(ST* ps);

STDataType StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);


void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
void StackDestory(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity==ps->top)
	{
		int newcapcaity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->a = (STDataType*)realloc(ps->a, newcapcaity * sizeof(STDataType));
		if (ps->a==NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->capacity = newcapcaity;
	}
	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;
}

bool isValid(char * s){
    ST MY_st;
    StackInit(&MY_st);
    while(*s)
    {
        if(*s=='('||*s=='['||*s=='{')
        {
            StackPush(&MY_st, *s);
        }
        else
        {
            if(StackEmpty(&MY_st))
            {
                StackDestory(&MY_st);
                return false;
            }

            char tmp = StackTop(&MY_st);

            if((tmp=='('&&*s!=')')||(tmp=='['&&*s!=']')||(tmp=='{'&&*s!='}'))
            {
                StackDestory(&MY_st);
                return false;
            }
            StackPop(&MY_st);
        }
        s++;
    }

    if(StackEmpty(&MY_st))
    {
        StackDestory(&MY_st);
        return true;
    }
    else
    {
        StackDestory(&MY_st);
        return false;
    }

}

题目2.用队列实现栈

题目链接

思路:
为了满足栈的特性,即最后入栈的元素最先出栈,在使用队列实现栈时,应满足队列前端的元素是最后入栈的元素。可以使用两个队列实现栈的操作,
入栈操作时,首先将元素入队到 q1,然后出栈时先将q1的n-1个元素依次出队并入队到 q2
,此时q1仅剩的那一个元素即为栈顶元素,出队即可。此时q1没有元素了
下一次想出栈的时候就再倒一次,也就是把q2的前n-1个元素出队并入队到q1,然后q2把剩下的那个元素出队即可,此时q2为空下一次再入栈的时候,也就不用管q1还是q2,就直接谁有元素就往谁的里面入队元素即可。
总结:出栈倒一下,入栈入非空。

在这里插入图片描述

实现代码:

typedef int QDataType;

typedef struct QueueNode
{
	struct Queue* 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);//判断有效元素个数


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

void QueueDestroy(Queue* pq)//队列的销毁
//head->node->node->node->node->node->node->tail//单链表的结构
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;
		free(del);
	}
	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)//入队
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode==NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else
	{
		newnode->data=x;
		newnode->next = NULL;
	}

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = pq->tail->next;//pq->tail=newnode;
	}
	pq->size++;
}

void QueuePop(Queue* pq)//出队
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* del = pq->head;
		pq->head = pq->head->next;
		free(del);
		del = NULL;
	}
	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&&pq->tail == NULL;//
}

int QueueSize(Queue* pq)//判断有效元素个数
{
	assert(pq);

	return pq->size;
}

typedef struct {
    Queue q1;
    Queue 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))
    {
        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;
    }
    int num=QueueSize(nonEmpty);
    if(nonEmpty==NULL)
    {
        return;
    }
    while(num>1)
    {
        QueuePush(Empty,QueueFront(nonEmpty));
        QueuePop(nonEmpty);
        num--;
    }
    int tmp=QueueFront(nonEmpty);
    QueuePop(nonEmpty);
    return tmp;
}

int myStackTop(MyStack* obj) {
    Queue* Empty=&obj->q1;
    Queue* nonEmpty=&obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        nonEmpty=&obj->q1;
        Empty=&obj->q2;
    }
    return QueueBack(nonEmpty);
}

bool myStackEmpty(MyStack* obj) {
    if(&obj->q1==NULL||&obj->q2==NULL)
    {
        return true;
    }
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q1);
    free(obj);
}

题目3.用栈实现队列

题目链接

思路:
一个队列是 FIFO 的,但一个栈是 LIFO 的。
这就意味着最新压入的元素必须得放在栈底。为了实现这个目的,我们创建两个栈一个专门用来进元素(pushST),一个用来出元素(popST),入队时只往pushST里存放元素,要出队时先把pushST中所有的元素移到popST 中,直接从 popST 弹出就可以了,
注意:当popST不为空的情况下是不需要从pushST里往popST中倒元素的。要出队时直接从popST里出栈即可。
这样设计可以避免来回颠倒元素,减少不必要的麻烦。

在这里插入图片描述
实现代码:

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;
}ST;

void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps, STDataType x);
void StackPop(ST* ps);

STDataType StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
void StackDestory(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity==ps->top)
	{
		int newcapcaity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		ps->a = (STDataType*)realloc(ps->a, newcapcaity * sizeof(STDataType));
		if (ps->a==NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->capacity = newcapcaity;
	}
	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;
}

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


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

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

int myQueuePop(MyQueue* obj) {
    int tmp=0;
    if(!StackEmpty(&obj->popST))
    {
        tmp=StackTop(&obj->popST);
        StackPop(&obj->popST);
    }
    else
    {
        while(!StackEmpty(&obj->pushST))/犯错之处!!!!!!!!!!!!
        {
        StackPush(&obj->popST,StackTop(&obj->pushST));
        StackPop(&obj->pushST);
        }
        tmp=StackTop(&obj->popST);
        StackPop(&obj->popST);
    }
    return tmp;
}

int myQueuePeek(MyQueue* obj) {
    
    
    if(StackEmpty(&obj->popST)&&!StackEmpty(&obj->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) {
    free(obj);
}

题目4.设计循环队列

题目链接
思路:
循环队列可用链表实现也可以用数组实现,链表要实现“循环”直接让最后结点的那个next域指向头结点即可,但是用数组实现的话怎么实现循环呢?
有效个数为k个(为了解决判空和判满,多留出了一个空间,有效个数为k,实际数组个数为k+1),数组的队头元素下标为front,队尾元素下一个位置的下标为back,(也有书上写front是对头元素的前一个,队尾元素为back,判空判满的表达式一样。)
每次入队的时候先要判断当先队列是否是满的,不为满,让back当前位置赋值要入队的元素,然后back正常++往后走,关键的来了再进行back=back %(k+1)操作即可实现循环。
那怎么区分什么时候空和什么时候满呢?
解决方法:
1、加一个size来记录当前元素的个数。
2、增加一个空间, 假如说长度4,那么就开5个空间,back位置下一个是front就满了(这样做是为了更好的区分队空和队满),所以说满的时候永远留一个空位置。

我们这里用第二种方法。
判断空:
当front和back相等的时候为空。

判断满:
当back的下一个为front时,即(back+1)%k+1和front相等的时候就是满了。
这个比较难想,可以看下面的动图:
下图的k应该是5,这里画错了。
在这里插入图片描述

实现代码:

typedef struct {
    int*a;
    int front;
    int back;
    int N;

} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
     MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
     obj->a=(int *)malloc(sizeof(int)*(k+1));///犯错之处!!!!!!!!
     obj->front=obj->back=0;
     obj->N=k+1;

     return obj;
}

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

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return ((obj->back)+1)%obj->N==obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->back]=value;
    obj->back++;
    obj->back%=obj->N;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front%=obj->N;
    return true;
}

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    int tmp=(obj->back-1+obj->N)%obj->N;
    return obj->a[tmp];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    
    free(obj);
    
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有效的放假者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值