栈常见的面试题

之前我们学习了栈,现在介绍一下栈常见的面试题。
常见面试题之一:
最小栈

实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间 复杂度为O(1)
关于如何实现最小栈,我们有两种思路。
思路一:我们设置两个栈,一个栈存放最小元素,另外一个栈存放栈内的数据。
思路二:我们利用一个栈,每次入栈时都入两个元素,第一个是要入栈的元素,出栈时也出两个元素,这样,栈顶元素就一直是最小元素。

这里写图片描述
其实思路一和思路二的思想是一样的,接下来我们用代码来实现一下思路二。
这部分关于链式栈的操作我就不在这里赘述了,详细的介绍可以看
我的博客:链式栈的基本操作


#include"linkstack.h"

void LinkStackInit(LinkStack* q){
    if(q == NULL){
        return;
    }
    q->head = NULL;
    q->tail = NULL;
    return;
}

LinkNode* LinkStackCreateNode(LinkStackType value){
    LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));
    if(new_node == 0){
        return NULL;
    }
    new_node->next = NULL;
    new_node->data = value;
    return new_node;
}

void DestroyNode(LinkNode* to_delete){
    if(to_delete == NULL){
        return;
    }
    free(to_delete);
    return;
}

void LinkStackPush(LinkStack* q,LinkStackType value){
    if(q == NULL){
        return;
    }
    LinkNode* new_node = LinkStackCreateNode(value);
    if(q->head == NULL){
        q->head = new_node;
        q->tail = new_node;
        return;
    }
    q->tail->next = new_node;
    q->tail = q->tail->next;
    return;
}

void LinkStackPrint(LinkStack* q,const char* msg){
    if(q == NULL){
        return;
    }
    printf("[ %s ]:\n",msg);
    LinkNode* cur = q->head;
    while(cur != NULL){
        printf("[%c][%p]->",cur->data,cur);
        cur = cur->next;
    }
    printf("NULL\n\n");
    return;
}

void LinkStackPop(LinkStack* q){
    if(q == NULL){
        return;
    }
    if(q->head == NULL){
        return;
    }
    LinkNode* temp = q->tail;
    LinkNode* cur = q->head;
    while(cur->next != q->tail){
        cur = cur->next;
    }
    q->tail = cur;
    q->tail->next = NULL;
    DestroyNode(temp);
    return;
}

int LinkStackFront(LinkStack* q,LinkStackType* value){
    if(q == NULL){
        return 0;
    }
    *value = q->tail->data;
    return 1;
}


//接下来是最小栈的具体实现

void MinStackPush(LinkStack* q,LinkStackType value){
    if(q == NULL){
        return;
    }
    if(q->head == NULL){
    //如果栈为空,默认第一个元素就是最小值,入栈两次
        LinkNode* new_node1 = LinkStackCreateNode(value);
        LinkNode* new_node2 = LinkStackCreateNode(value);
        q->head = new_node1;
        q->head->next = new_node2;
        q->tail = new_node2;
        return;
    }
    LinkStack* cur = q;

    //如果栈顶元素大于value说明value就是当前栈最小的值
    if(cur->tail->data > value){
        LinkNode* new_node1 = LinkStackCreateNode(value);
        LinkNode* new_node2 = LinkStackCreateNode(value);
        cur->tail->next = new_node1;
        cur->tail = cur->tail->next;
        cur->tail->next = new_node2;
        cur->tail = cur->tail->next;
        return;
    }else{
        LinkNode* new_node1 = LinkStackCreateNode(value);
        LinkNode* new_node2 = LinkStackCreateNode(cur->tail->data);
        cur->tail->next = new_node1;
        cur->tail = cur->tail->next;
        cur->tail->next = new_node2;
        cur->tail = cur->tail->next;
        return;
    }
    return;
}

void MinStackPop(LinkStack* q){
    if(q == NULL){
        return;
//每次出栈两个元素
    LinkStackPop(q);
    LinkStackPop(q);
    return;
}

//这里我们采用输出型参数 value 将最小值取出来
int MinStack(LinkStack* q,LinkStackType* value){
    if(q == NULL || value == NULL){
        return 0;
    }
    *value = q->tail->data;
    printf("栈顶元素是:%c\n",q->tail->data);
    return 1;
}

常见栈的面试题之二:
使用两个栈实现一个队列

关于两个栈实现一个队列,栈是先进后出,队列是先进先出,所以我们考虑建立两个栈,每次将一个栈的元素出栈然后入栈第二个栈,这样再出栈第二个栈的元素就是前面先入栈的元素了,这样就可以模拟出来一个队列。但是考虑到一次队列后再入队列的时候可能导致顺序混乱,我们需要将第二个栈里的元素入栈回第一个栈才能继续入队列。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

接下来,我们用代码来实现一下上面的过程:

#include"linkstack.h"

void LinkStackInit(LinkStack* q){
    if(q == NULL){
        return;
    }
    q->head = NULL;
    q->tail = NULL;
    return;
}

LinkNode* LinkStackCreateNode(LinkStackType value){
    LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));
    if(new_node == 0){
        return NULL;
    }
    new_node->next = NULL;
    new_node->data = value;
    return new_node;
}

void DestroyNode(LinkNode* to_delete){
    if(to_delete == NULL){
        return;
    }
    free(to_delete);
    return;
}

void LinkStackPush(LinkStack* q,LinkStackType value){
    if(q == NULL){
        return;
    }
    LinkNode* new_node = LinkStackCreateNode(value);
    if(q->head == NULL){
        q->head = new_node;
        q->tail = new_node;
        return;
    }
    q->tail->next = new_node;
    q->tail = q->tail->next;
    return;
}

void LinkStackPrint(LinkStack* q,const char* msg){
    if(q == NULL){
        return;
    }
    printf("[ %s ]:\n",msg);
    LinkNode* cur = q->head;
    while(cur != NULL){
        printf("[%c][%p]->",cur->data,cur);
        cur = cur->next;
    }
    printf("NULL\n\n");
    return;
}

void LinkStackPop(LinkStack* q){
    if(q == NULL){
        return;
    }
    if(q->head == NULL){
        return;
    }
    LinkNode* temp = q->tail;
    LinkNode* cur = q->head;
    if(temp == cur){
        DestroyNode(temp);
        q->head = NULL;
        return;
    }
    while(cur->next != q->tail){
        cur = cur->next;
    }
    q->tail = cur;
    q->tail->next = NULL;
    DestroyNode(temp);
    return;
}

int LinkStackFront(LinkStack* q,LinkStackType* value){
    if(q == NULL){
        return 0;
    }
    *value = q->tail->data;
    return 1;
}

//交换栈元素栈内元素
void ChangeStack(LinkStack* q1, LinkStack* q2){
    if(q1 == NULL || q2 == NULL){
        return;
    }
    LinkStackType value;
    while(q2->tail != q2->head){
        value = q2->tail->data;
        LinkStackPop(q2);
        LinkStackPush(q1, value);
    }
    value = q2->head->data;
    LinkStackPop(q2);
    LinkStackPush(q1, value);
    return;
}

void QueueByStackPush(LinkStack* q1, LinkStack* q2,  LinkStackType value ){
    if(q1 == NULL || q2 == NULL){
        return;
    }

    //入栈时判断哪个栈是空的,将不是空的栈的元素导入到空的栈
    if(q1->head == NULL && q2->head != NULL){
        ChangeStack(q1, q2);
        LinkStackPush(q1, value);
        ChangeStack(q2, q1);
        return;
    }else{
        LinkStackPush(q1,value);
        ChangeStack(q2, q1);
        return;
    }
    return;
}

void QueueByStackPop(LinkStack* q1,LinkStack* q2){
    if(q1 == NULL || q2 == NULL){
        return;
    }
    //出栈只要将栈2的栈定元素出栈就ok
    LinkStackPop(q2);
    return;
}

常见题型之三
两个队列实现一个栈
在这道题目中我们考虑到栈是先进后出的,而队列是先进先出的,因此,我们同样考虑用两个队列来模拟实现一个栈。首先将不为空的一个队列的元素出队列到另外一个队列,直到该队列只剩一个元素,然后将该元素出栈,我们就模拟实现了先进先出,也就是队列的基本形式。
这里写图片描述

#include"linkqueue.h"

void LinkQueueInit(LinkQueue* q){
    if(q == NULL){
        return;
    }
    q->head = NULL;
    q->tail = NULL;
    return;
}

LinkNode* LinkQueueCreateNode(LinkQueueType value){
    LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));
    if(new_node == 0){
        return NULL;
    }
    new_node->next = NULL;
    new_node->data = value;
    return new_node;
}

void DestroyNode(LinkNode* to_delete){
    if(to_delete == NULL){
        return;
    }
    free(to_delete);
    return;
}

void LinkQueuePush(LinkQueue* q,LinkQueueType value){
    if(q == NULL){
        return;
    }
    LinkNode* new_node = LinkQueueCreateNode(value);
    if(q->head == NULL){
        q->head = new_node;
        q->tail = new_node;
        return;
    }
    q->tail->next = new_node;
    q->tail = q->tail->next;
    return;
}

void LinkQueuePrint(LinkQueue* q,const char* msg){
    if(q == NULL){
        return;
    }
    printf("[ %s ]:\n",msg);
    LinkNode* cur = q->head;
    while(cur != NULL){
        printf("[%c][%p]->",cur->data,cur);
        cur = cur->next;
    }
    printf("NULL\n\n");
    return;
}

void LinkQueuePop(LinkQueue* q){
    if(q == NULL){
        return;
    }
    if(q->head == NULL){
        return;
    }
    LinkNode* temp = q->head;
    q->head = q->head->next;
    DestroyNode(temp);
    return;
}

int LinkQueueFront(LinkQueue* q,LinkQueueType* value){
    if(q == NULL){
        return 0;
    }
    *value = q->head->data;
    return 1;
}

//#######################################################################################################
//############################# 两个队列实现一个栈 ######################################################
//#######################################################################################################

//搬移两个队列的内容,直到一个队列只剩一个元素
LinkQueue* MvStackByQueue(LinkQueue* from, LinkQueue* to){
    if(from == NULL || to == NULL){
        return NULL;
    }
    LinkQueueType value;
    while(from->head != from->tail){
       value =  from->head->data;
       LinkQueuePop(from);
       LinkQueuePush(to,value);
    }
    return from;
}

void StackByQueuePush(LinkQueue* from, LinkQueue* to, LinkQueueType value){
    if(from == NULL || to == NULL){
        return;
    }
    if(from->head == NULL && to->head != NULL){
        LinkQueuePush(to, value);
        return;
    }else{
        LinkQueuePush(from, value);
    }
    return;
}

int StackByQueuePop(LinkQueue* from, LinkQueue* to, LinkQueueType* value){
    if(from == NULL || to == NULL || value == NULL){
        return 1;
    }
    if(from->head == NULL && to->tail != NULL){
        LinkQueue* top = MvStackByQueue(to, from);
        *value = top->head->data;
        LinkQueuePop(to);
    }else{
        LinkQueue* top = MvStackByQueue(from, to);
        *value = top->head->data;
        LinkQueuePop(from);
    }
    return 1;
}

常见栈的面试题之四
共享栈
一个数组实现两个栈(共享栈)
这里写图片描述
设置两个指针top1 和 top2分别指向数组头和数组尾,插入元素的时候两个指针分别向中间移动,当两个指针相遇的时候说明共享栈已满。
代码的实现需要参考栈的范围设置。
这里,我们设置栈一的取值范围是[0, top1),栈二的取值范围时候[top2,MAXSIZE)
具体实现如下:

#include"share_stack.h"

void ShareStackInit(ShareStack* stack){
    if(stack == NULL){
        return;
    }
    stack->top1 = 0;
    stack->top2 = ShareStackMaxSize;
    return;
}

void ShareStackPush1(ShareStack* stack, ShareStackType value){
    if(stack == NULL){
        return;
    }
    if(stack->top1 >= stack->top2){
        //栈满
        return;
    }
    stack->data[stack->top1++] = value;
    return;
}

void ShareStackPush2(ShareStack* stack,ShareStackType value ){
    if(stack == NULL){
        return;
    }
    if(stack->top1 >= stack->top2){
        return;
    }
    stack->data[--stack->top2] = value;
    return;
}

void ShareStackPop1(ShareStack* stack){
    if(stack == NULL){
        //非法输入
        return;
    }
    if(stack->top1 == 0){
        //空栈
        return;
    }
    --stack->top1;
    return;
}

void ShareStackPop2(ShareStack* stack){
    if(stack == NULL){
        //非法输入
        return;
    }
    if(stack->top2 == ShareStackMaxSize){
        //空栈
        return;
    }
    ++stack->top2;
}

int ShareStackTop1(ShareStack* stack, ShareStackType* value){
    if(stack == NULL || value == NULL){
        return 0;
    }
    if(stack->top1 == 0){
        return 0;
    }
    *value = stack->data[--stack->top1];
    return 1;
}

int ShareStackTop2(ShareStack* stack, ShareStackType* value){
    if(stack == NULL || value == NULL){
        return 0;
    }
    if(stack->top2 == ShareStackMaxSize){
        return 0;
    }
    *value = stack->data[stack->top2];
    return 1;
}

以上就是栈的常见部分面试题解答,由于本人能力有限,可能在上面的介绍中有一些不妥或者bug,欢迎发邮件到我的邮箱(Cyrus_wen@163.com)批评指正!

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值