之前我们学习了栈,现在介绍一下栈常见的面试题。
常见面试题之一:
最小栈
实现一个栈,要求实现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)批评指正!