栈和队列面试题

本文详细介绍了栈和队列的一些经典面试题,包括最小栈的两种实现方式,两个栈模拟队列,两个队列实现一个栈,判断字符串是否按照出栈顺序以及共享栈的实现。通过具体的代码实现解析了这些数据结构问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、最小栈
最小栈其实和栈没有什么区别的,唯一的区别在于最小栈是可以在O(1)时间内得到当前的栈空间里,最小的值。解决这个问题提供两种方法:
Round1:
创建一个辅助栈,比较当前元素和辅助元素栈顶元素的大小 ,如果大于辅助栈栈顶元素,则不理会,反之则需要压入辅助栈。此时辅助栈的栈顶元素就是该栈的最小值。
代码实现如下(栈的操作在可参考前面写的博客–栈的实现):

void SqStackMin1(SqStack *sq1,SqStack *sq2,int flag,SqStackType value){
    if(sq1 == NULL || sq2 == NULL){
        return;                                                                                                                                                   
    }
    if(flag == 1){
        if(sq1 -> size == 1){
            SqStackPush(sq2,value);
        }
        //比较当前元素和辅助元素栈顶元素的大小
        //如果大于辅助栈栈顶元素,则不理会
        //反之则需要压入辅助栈
        else{
            SqStackType cur1 = SqStackTopValue(sq2);
            if(value > cur1){
                return;
            }
            else{
                SqStackPush(sq2,value);
            }
        }
    }
    else if(flag == 0){
        SqStackType cur2 = SqStackTopValue(sq2);
        if(value > cur2){
            return;
        }else{
            SqStackPop(sq2);
        }
    }
}
void SqStackPush1(SqStack *sq1, SqStack *sq2, SqStackType value){
    if(sq1 == NULL || sq2 == NULL){
        return;
    }
    if(sq1 -> size > sq1 -> capacity){
        SqStackResize(sq1);
    }
    sq1 -> data[sq1 -> size] =  value;
    sq1 -> size++;
    SqStackMin1(sq1,sq2,1,value);

}
void SqStackPop1(SqStack *sq1, SqStack *sq2){
    if(sq1 == NULL || sq2 == NULL){
        return;
    }
    if(sq1 -> size == 0){
        return;
    }
    SqStackType tmp = SqStackTopValue(sq1);
    SqStackMin1(sq1,sq2,0,tmp);
    sq1 -> size--;
}

Round2:
既然我们需要在O(1)时间内得到当前的栈空间里,最小的值,我们可以把最小的值放在栈顶即可实现要求,但是这样就破坏了入栈顺序,那如何实现?
我们可以每次入栈的时候入两次,第一次入栈是需要入栈的值,第二次入栈的元素和上次(本两次入栈的前一次)的元素进行比较,如果比其大,则第二次入栈的元素为上一次两次入栈第二次的元素,如果小,第二次入栈的元素就是第一次入栈的元素的值。出栈的时候就需要每次出栈两次。说的有些绕,可以看看代码来理解。
代码实现如下:

void SqStackPush2(SqStack *sq,SqStackType value){
    if(sq == NULL){
        return;
    }
    if(sq -> size == 0){
        sq -> data[sq -> size] = value;
        sq -> size++;
        sq -> data[sq -> size] = value;
        sq -> size++;
    }
    SqStackType tmp = SqStackTopValue(sq);
    if(value > tmp){                                                                                                                                              

        SqStackPush(sq,value);
        SqStackPush(sq,tmp);
    }else{
        SqStackPush(sq,value);
        SqStackPush(sq,value);
    }
}
void SqStackPop2(SqStack *sq){
    if(sq == NULL){
        return;
    }
    if(sq -> size == 0){
        return;
    }
    SqStackPop(sq);
    SqStackPop(sq);
}
SqStackType SqStackGetTop(SqStack* sq){
    //栈顶元素是最小值
    SqStackType min = SqStackTopValue(sq);
    return min;
}

二、两个栈实现一个队列
栈和队列的根本区别就是,栈是后进先出,队列是先进先出。因此用两个栈实现一个队列,就是需要用两个栈来实现先进先出这种情况,那如何实现呢?
首先我们定义两个栈input和output,实现入队操作是非常简单的,只要入input栈即可,当实现出队列的时候,我们首先将input内的元素一次出栈,然后依次入栈output,然后再让output出栈,这样就实现了队列的出队列操作。

具体代码实现如下:

typedef SqStackType QueueType;

typedef struct Queue{
    SqStack input;
    SqStack output;
}Queue;

void QueueInit(Queue* q){ 
    if(q == NULL){
        return;
    }   
    InitSqStack(&q -> input);
    InitSqStack(&q -> output);
}

void QueuePush(Queue* q, QueueType value){
    if(q == NULL){
        return;
    }   
    QueueType tmp;
    while(SqStackTop(&q -> output, &tmp)){
        SqStackPop(&q -> input);
        SqStackPush(&q -> output, tmp);
    }   
    SqStackPush(&q -> input, value);
}

void QueuePop(Queue* q){
    if(q == NULL){
        return;
    }
    QueueType tmp;
    while(SqStackTop(&q -> input, &tmp)){
        SqStackPop(&q -> output);
        SqStackPush(&q -> input, tmp);
    }
    SqStackPop(&q -> output);
}

int QueueFront(Queue* q, QueueType* value){
    if(q == NULL || value == NULL){
        return 0;
    }
    QueueType tmp;
    while(SqStackTop(&q -> input, &tmp)){
        SqStackPop(&q -> input);
        SqStackPush(&q -> output, tmp);

    }
    int ret = SqStackTop(&q -> output, value);
    return ret;
}
////////////////////////////////////
///////////TEST//////////////////
//////////////////////////////////


void Test(){
    Queue q;
    QueueInit(&q);
    QueuePush(&q,'a');
    QueuePush(&q,'b');
    QueuePush(&q,'c');
    QueuePush(&q,'d');

    QueueType tmp;
    QueueFront(&q,&tmp);
    printf("tmp excepted a,actual %c\n",tmp);
    QueuePop(&q);
    QueueFront(&q,&tmp);
    printf("tmp excepted b,actual %c\n",tmp);
    QueuePop(&q);
    QueueFront(&q,&tmp);
    printf("tmp excepted c,actual %c\n",tmp);
    QueuePop(&q);
    QueueFront(&q,&tmp);
    printf("tmp excepted d,actual %c\n",tmp);
    QueuePop(&q);
    return;
}

int main(){
    Test();                                                                                                                                                      
    return 0;
}


三、两个队列实现一个栈
用两个队列实现一个栈,跟用两个栈实现一个队列思路大体相同,只有出栈方面稍有差别,要使队列的先进先出变为栈的后进先出,我们先定义两个队列queue1,queue2,先将元素入栈到queueu1中,出栈时,除queue1的第一个元素外,其余元素移入到queue2中,然后出栈queue1中的那个元素,再次出栈的时候就使queue1和queue2相互颠倒操作即可,这样就实现了栈后进先出的特点了。

具体代码实现如下(队列操作详见博客–队列的实现)

#include <stdio.h>
#include "SqQueue.h"

typedef SqQueueType StackType;

typedef struct Stack{
    SqQueue queue1;
    SqQueue queue2;
}Stack;

void StackInit(Stack* stack){
    if(stack == NULL){
        return;
    }   
    SqQueueInit(&stack -> queue1);
    SqQueueInit(&stack -> queue2);
}
void StackPush(Stack* stack,StackType value){
    if(stack == NULL){
        return;
    }   
    SqQueue* entry = SqQueueSize(&stack -> queue1) > 0 ? &stack -> queue1 : &stack -> queue2;
    SqQueuePush(entry, value);
}
void StackPop(Stack* stack){
    if(stack == NULL){
        return;//非法输入
    }
    size_t size1 = SqQueueSize(&stack -> queue1);
    size_t size2 = SqQueueSize(&stack -> queue2);
    if(size1 == 0 && size2 == 0){
        return;
    }
    SqQueue* exit = size1 > 0 ? &stack -> queue1 : &stack -> queue2;
    SqQueue* backup = size1 == 0 ? &stack -> queue1 : &stack -> queue2;
    while(SqQueueSize(exit) > 1){
        StackType tmp;
        SqQueueFront(exit, &tmp);
        SqQueuePop(exit);
        SqQueuePush(backup, tmp);
    }int StackTop(Stack* stack, StackType* value){
    if(stack == NULL || value == NULL){
        return 0;
    }
    size_t size1 = SqQueueSize(&stack -> queue1);
    size_t size2 = SqQueueSize(&stack -> queue2);
    if(size1 == 0 && size2 == 0){
        return 0;
    }
    SqQueue* non_empty = size1 > 0 ? &stack -> queue1 : &stack -> queue2;
    SqQueue* empty = size1 == 0 ? &stack -> queue1 : &stack -> queue2;
    StackType tmp;
    while(SqQueueSize(non_empty) > 0){
        SqQueueFront(non_empty, &tmp);
        SqQueuePop(non_empty);
        SqQueuePush(empty, tmp);
    }
    *value = tmp;
    return 1;
}
op(exit);
}
/
/TEST///
/

void Test(){
    Stack stack;
    StackInit(&stack);
    StackPush(&stack, 'a');
    StackPush(&stack, 'b');
    StackPush(&stack, 'c');
    StackPush(&stack, 'd');

    StackType tmp;
    StackTop(&stack, &tmp);
    printf("tmp expected d, actual %c\n", tmp);
    StackPop(&stack);
    StackTop(&stack, &tmp);
    printf("tmp expected c, actual %c\n", tmp);
    StackPop(&stack);
    StackTop(&stack, &tmp);
    printf("tmp expected b, actual %c\n", tmp);
    StackPop(&stack);
    StackTop(&stack, &tmp);
    printf("tmp expected a, actual %c\n", tmp);
    StackPop(&stack);
}

int main(){
    Test();
    return 0;                                                                                                                                                    
}

四、判断字符串是否按照出栈顺序
首先来了解下题目的大致意思
给定一个字符串,如:a b d e c
一个栈的入栈顺序为:a b c d e
那么出栈顺序显而易见:e d c b a
题目意思为:字符串 a b d e c 是否能按出栈顺序所打出。比如说,我们先入栈a元素,接着再将a元素出栈,则得到a元素,接着再入b元素,同理出栈,再入c元素,发现与字符串d元素并不一致,那么继续入栈,入d元素,发现与字符串元素一致,继续出栈,依次类推,最终得到我们的字符串abdef,不过整个过程中,我们只执行了入栈出栈操作,并没有改变其入栈出栈的顺序。这就是所要考的内容,给定任意入栈顺序,任意字符串,判断字符串是否能够根据入栈出栈操作得到即可。

这里我们的思路大致是,每次入栈后取栈顶元素与字符串比较,如果一致则出栈栈顶元素,接着比较下一个栈顶是否与字符串第二个元素一致,如果不一致,继续入栈,以此类推,直至入栈结束,或者是字符串到最后一个元素,即可判断。

代码实现如下:

#include <stdio.h>                                                                                                                                               
#include "SqStack.h"

int Str_Stack(SqStack* sq,char* str1, char* str2, int len){
    if(str1 == NULL || str2 == NULL){
        return 0;
    }   
    SqStackType value;
    int i = 0;
    for(; i < len; i++){
        SqStackPush(sq, *str1);
        SqStackTop(sq, &value);
        while(value == *str2){
            SqStackPop(sq);
            SqStackTop(sq, &value);
            str2++;
        }   
        if(*str2 == '\0'){
            return 1;
        }   
        str1++;
    }   
    return 0;
}
int main()
{
    SqStack sq;
    InitSqStack(&sq);
    int ret;
    char str1[5] = {'a', 'b', 'c', 'd', 'e'};
    char str2[5] = {'a', 'c', 'd', 'e', 'b'};
    char str3[5] = {'a', 'd', 'b', 'e', 'c'};
    int len = sizeof(str1)/sizeof(str1[0]);

    ret = Str_Stack(&sq, str1, str2, len);
    printf("expected ret 1,actual ret %d\n",ret);

    ret = Str_Stack(&sq, str1, str3, len);
    printf("expected ret 0,actual ret %d\n",ret);

    return 0;

}                            

五、共享栈(一个数组实现两个栈)

这里写图片描述

如图,我们可以定义两个指针分别指向数组的头和尾,然后分别作为两个栈的开始,两个栈每次入栈时,head栈从前往后增长,即head++,tail栈从后往前增长,即tail- -,当head >= tail时,共享栈就满了。

代码实现如下:

//sharedstack.h
#pragma once                                                                                                                                                       
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

typedef char StackType;

typedef struct Stack{
    StackType data[MAXSIZE];
    size_t head;
    size_t tail;
}Stack;

void SharedStackInit(Stack* s);

void SharedStackPush1(Stack* s, StackType value);

void SharedStackPush2(Stack* s, StackType value);

void SharedStackPop1(Stack* s);

void SharedStackPop2(Stack* s);

int SharedStackTop1(Stack* s, StackType* vlaue);

int SharedStackTop2(Stack* s, StackType* vlaue);

void ShareStackDestroy(Stack* s);

void ShareStackDestroy(Stack* s);


//sharedstack.c
#include <stdio.h>                                                                                                                                                 
#include "sharedstack.h"
#include "SqStack.h"

void SharedStackInit(Stack* s){ 
    if(s == NULL){
        return;//非法输入
    }    
    s -> head = 0;
    s -> tail = MAXSIZE;
} 

void SharedStackPush1(Stack* s, StackType value){
    if(s == NULL){
        return;//非法输入
    }   
    if(s -> head >= s -> tail){
        return;//共享栈满
    }   
    s -> data[s -> head++] = value;
}

void SharedStackPush2(Stack* s, StackType value){
    if(s == NULL){
        return;//非法输入
    }   
    if(s -> head >=  s -> tail){
        return;//共享栈满
    }   
    s -> data[--s -> tail] = value;
}
void SharedStackPop1(Stack* s){
    if(s == NULL){
        return;//非法输入
    }
    if(s -> head == 0){
        return;//空栈
    }
    --s -> head;
    return;
}

void SharedStackPop2(Stack* s){
    if(s == NULL){
        return;//非法输入
    }
    if(s -> tail == MAXSIZE){
        return;//空栈
    }
    ++s -> tail;
    return;
}

int SharedStackTop1(Stack* s, StackType* value){
    if(s == NULL || value == NULL){
        return 0;//非法输入
    }
    if(s -> head == 0){
        return 0;//栈空
    }
    *value = s -> data[s -> head - 1];                                                                                                                             
    return 1;
}
int SharedStackTop2(Stack* s, StackType* value){
    if(s == NULL || value == NULL){
        return 0;//非法输入
    }
    if(s -> tail == MAXSIZE){
        return 0;//栈空
    }
    *value = s -> data[s -> tail];
    return 1;

}


///////////////////////////////////////////
///////////////////TEST///////////////////
//////////////////////////////////////////

#if 1
#define TESTHEAD printf("================%s==============\n", __FUNCTION__)

void PrintChar(Stack* s,const char* msg){
    printf("############%s##############\n", msg);
    if(s == NULL){
        return;//非法输入
    }
    printf("头部栈\n");
    size_t i = 0;
    for(; i < s -> head; ++i){
        printf("%c\n", s -> data[i]);
    }
    printf("尾部栈\n");
    size_t j = MAXSIZE;
    for(; j > s -> tail; --j){
        printf("%c\n", s -> data[j - 1]);
    }
}

void TestInit(){
    TESTHEAD;  
    Stack s;
    SharedStackInit(&s);
    PrintChar(&s, "初始化栈");
    printf("head expect 0,actual %lu\n", s.head);
    printf("tail expect 10, actual %lu\n", s.tail);
}
void Test(){
    TESTHEAD;
    Stack s;
    SharedStackInit(&s);
    SharedStackPush1(&s,'a');
    SharedStackPush1(&s,'b');
    SharedStackPush1(&s,'c');
    SharedStackPush1(&s,'d');
    SharedStackPush2(&s,'e');
    SharedStackPush2(&s,'f');
    SharedStackPush2(&s,'g');
    SharedStackPush2(&s,'h');
    SharedStackPush2(&s,'i');

    PrintChar(&s, "进栈");
    SharedStackPop1(&s);
    SharedStackPop2(&s);
    PrintChar(&s, "出栈");

    StackType tmp1 ;
    StackType tmp2;
    int ret1 = SharedStackTop1(&s, &tmp1);
    int ret2 = SharedStackTop2(&s, &tmp2);
    printf("ret1 expect 1,actual %d\n", ret1);
    printf("tmp1 expect c, actaual %c\n", tmp1);
    printf("ret2 expect 1,actual %d\n", ret2);
    printf("tmp2 expect h, actaual %c\n", tmp2);
}

int main(){                                                                                                                                                        
    TestInit();
    Test();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值