栈和队列面试题
1、实现一个栈,要求实现push(入栈),pop(出栈),Min(返回最小值)的时间复杂度为O(1)
方式1:给定两个栈,一个栈保存数据,一个栈保存最小值。取一个数据,压入数据栈中,同时向最小值栈中存入一个数据。取下一个数据,若是下一个数据小于最小值栈中的栈顶数据,则将该数据插入数据栈同时压入最小值栈中;否则压入数据栈中。
class Solution {
public:
void push(int value) {
StackInt.push(value);
if(StackMin.empty())
StackMin.push(value);
else if(StackMin.top()<value)
StackMin.push(StackMin.top());
else
StackMin.push(value);
}
void pop() {
if(!StackInt.empty())
{
StackInt.pop();
StackMin.pop();
}
}
int top() {
return StackInt.top();
}
int min() {
return StackMin.top();
}
private:
stack<int> StackInt;
stack<int> StackMin;
};
方式2:用一个栈实现:
(1)、压栈的时候,将一个相同的数据进栈两次,上面的那个数据表示数据,下面的元素表示最小值;继续压入下一个数据,并且用该元素与最小值进行比较:将该元素和当前最小值入栈,继续压入下面的元素……
实现代码:
# pragma once
# include"satck.h"
# include<assert.h>
//给出最小栈的操作
typedef struct MinStack
{
Stack s;//用栈实现
}MinStack;
void MStackInit(MinStack *ms)
{
assert(ms);
StackInit(&ms->s);
}
//获取最小值
MSDataType GetMinData(MinStack *ms)
{
return StackTop(&ms->s)._mindata;
}
void MStackPush(MinStack *ms, MSDataType data)
{
//给出元素
SElem elem;;
elem._data = elem._mindata = data;
if (!Stackempty(&ms->s))//栈里面有元素
{
MSDataType minData = GetMinData(ms);//获取最小值
//如果最小值小于data,更新最小值中的data
if (minData < data)
elem._mindata = data;
}
StackPush(&ms->s,elem);
}
int MSEmpty(MinStack *ms)
{
assert(ms);
return Stackempty(&ms->s);
}
void MStackPop(MinStack *ms)
{
assert(ms);
assert(!Stackempty(ms));
StackPop(&ms->s);
}
//获取最小元素
MSDataType MStackTop(MinStack *ms)
{
return StackTop(&ms->s)._data;
}
int MStackSize(MinStack *ms)
{
return StackSize(&ms->s);
}
void TestMinStack()
{
MinStack s;
MStackInit(&s);
MStackPush(&s, 2);
MStackPush(&s, 3);
MStackPush(&s, 4);
MStackPush(&s, 7);
MStackPush(&s, 5);
printf("size=%d\n", MStackSize(&s));
printf("top=%d\n", MStackTop(&s));
printf("min=%d\n", MStackMinData(&s));
MStackPop(&s);
MStackPop(&s);
printf("size=%d\n", MStackSize(&s));
printf("top=%d\n", MStackTop(&s));
printf("min=%d\n", MStackMinData(&s));
}
stack.h
# pragma oncee
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
#define MAX_SIZE 10
//栈里面放的元素
typedef int MSDataType;
typedef struct SElem
{
MSDataType _data;//数据
MSDataType _mindata;//最小值
}SElem;
typedef SElem DataTYpe;
typedef struct Stack
{
DataTYpe _array[MAX_SIZE];//有效元素的个数
int _top; //栈顶元素的位置
}Stack;
//初始化
void StackInit(Stack *s);
//入栈
void StackPush(Stack *s, DataTYpe data);
//出栈
void StackPop(Stack *s);
//取栈顶元素
DataTYpe StackTop(Stack *s);
//有效元素的个数
int StackSize(Stack *s);
//检测栈是否为空
int Stackempty(Stack *s);
2、使用两个栈实现一个队列
# pragma once
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
#define MAX_SIZE 10
typedef int DataTYpe;
typedef enum{
ADD,SUB,MUL,DIV,DATA
}OPERATE;
typedef struct Cell{
OPERATE _op;
int data;
}Cell;
typedef struct Stack
{
DataTYpe _array[MAX_SIZE];//有效元素的个数
int _top; //栈顶元素的位置
}Stack;
//初始化
void StackInit(Stack *s);
//入栈
void StackPush(Stack *s, DataTYpe data);
//出栈
void StackPop(Stack *s);
//取栈顶元素
DataTYpe StackTop(Stack *s);
//有效元素的个数
int StackSize(Stack *s);
//检测栈是否为空
int Stackempty(Stack *s);
//判断括号是否匹配
int CalRPN(Cell RPN[], int size);
# include<stdio.h>
# include<stdlib.h>
# include<assert.h>
# include"Stck.h"
typedef struct QueueBy2Stack
{
Stack _s1;
Stack _s2;
}QueueBy2Stack;
void QueueBy2StackInit(QueueBy2Stack *q)
{
assert(q);
StackInit(&q->_s1);
StackInit(&q->_s2);
}
void QueueBy2StackPush(QueueBy2Stack *q, QDataType data)
{
//入到第一个栈上,因为第一个栈为队尾
StackPush(&q->_s1, data);
}
void QueueBy2StackPop(QueueBy2Stack *q)
{
//如果队列中为空,则不能出队列
if (QueueBy2StackEmpty(&q->_s2))
return;
//第二个队列是栈头,首先判断第二个队列中有没有元素
if (Stackempty(&q->_s2))
{
//把第一个栈中的元素倒过去
while (!Stackempty(&q->_s1))
{
StackPush(&q->_s2, StackTop(&q->_s1));
StackPop(&q->_s1);
}
}
StackPop(&q->_s2);
}
QDataType QueueBy2StackFront(QueueBy2Stack *q)
{
//取对头即第二个栈的栈顶
//如果第二个栈是空的,把元素倒过去
//如果队列中为空,则不能出队列
if (QueueBy2StackEmpty(&q->_s2))
return;
//第二个栈是队头,首先判断第二个队列中有没有元素
if (Stackempty(&q->_s2))
{
//把第一个栈中的元素倒过去
while (!Stackempty(&q->_s1))
{
StackPush(&q->_s2, StackTop(&q->_s1));
StackPop(&q->_s1);
}
}
return StackTop(&q->_s2);
}
QDataType QueueBy2StackBackBack(QueueBy2Stack *q)
{
//取栈尾,看第一个栈中的数据是不是空的,如果是空的就把第二个栈中的数据倒过去
//如果队列中为空,则不能出队列
if (QueueBy2StackEmpty(&q->_s1))
return;
//第二个栈是队头,首先判断第二个队列中有没有元素
if (Stackempty(&q->_s2))
{
//把第一个栈中的元素倒过去
while (!Stackempty(&q->_s1))
{
StackPush(&q->_s1, StackTop(&q->_s2));
StackPop(&q->_s2);
}
}
StackPop(&q->_s1);
}
int QueueBy2StackSize(QueueBy2Stack *q)
{
return StackSize(&q->_s1) + StackSize(&q->_s2);
}
int QueueBy2StackEmpty(QueueBy2Stack *q)
{
//两个栈中都为空,则队列是空的
return Stackempty(&q->_s1) && Stackempty(&q->_s2);
}
void QueueTest()
{
QueueBy2Stack q;
QueueBy2StackInit(&q);
QueueBy2StackPush(&q, 1);
QueueBy2StackPush(&q, 2);
QueueBy2StackPush(&q, 3);
QueueBy2StackPush(&q, 4);
QueueBy2StackPush(&q, 5);
printf("size=%d\n", QueueBy2StackSize(&q));
printf("front=%d\n", QueueBy2StackFront(&q));
printf("back=%d\n", QueueBy2StackBack(&q));
QueueBy2StackPop(&q);
QueueBy2StackPop(&q);
QueueBy2StackPop(&q);
printf("size=%d\n", QueueBy2StackSize(&q));
printf("front=%d\n", QueueBy2StackFront(&q));
printf("back=%d\n", QueueBy2StackBack(&q));
}
int main()
{
QueueTest();
return 0;
}
3、使用两个队列实现一个栈
queue.h
# pragma once
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
# include<malloc.h>
typedef int QDataType;
typedef struct Node{
QDataType data;
struct Node *_pNext;
}Node,*pNode;
typedef struct Queue{
pNode _pHead;
pNode _pTail;
}Queue;
void QueueInit(Queue *q);
void QueuePush(Queue *q, QDataType data);
void QueuePop(Queue *q);
pNode QueueTop(Queue *q);
pNode QueueTail(Queue *q);
int QueueEmpty(Queue *q);
int QueueSize(Queue *q);
pNode BuyNode(QDataType data);
源文件:
# include<stdio.h>
# include<stdlib.h>
# include<assert.h>
# include"Queue.h"
typedef int DataType;
typedef struct StackBy2Queue
{
Queue _q1;
Queue _q2;
}StackBy2Queue;
void StackBy2QueueInit(StackBy2Queue* s)
{
assert(s);
QueueInit(&s->_q1);
QueueInit(&s->_q2);
}
void StackBy2QueuePush(StackBy2Queue* s, QDataType data)
{
//在这里把元素入到第一个队列里面去
QueuePush(&s->_q1, data);
}
void StackBy2QueuePop(StackBy2Queue* s)
{
//出队列,把元素倒到q2中去,直到q1中只剩下一个元素
//先判断栈是否为空,若是栈为空,则不能出
if (StackBy2QueueEmpty(s))
return;
//判断第二个队列里面有没有数据
if (!QueueEmpty(&s->_q1)){
//先把队列1中的数据倒队列2中,直到队列1中只剩下一个元素为止
while (QueueSize(&s->_q1) > 1){
QueuePush(&s->_q2, QueueFront(&s->_q1));
//第一个队列中的元素移走一个,即删除一个
QueueTop(&s->_q1);
}
//第一个队列中只剩一个元素,移除即可
QueuePop(&s->_q1);
}
//第二次出,第一个队列为空
else
{
while (QueueSize(&s->_q2) > 1){
QueuePush(&s->_q1, QueueFront(&s->_q2));
//第二个队列中的元素移走一个,即删除一个
QueueTop(&s->_q2);
}
//第二个队列中只剩一个元素,移除即可
QueuePop(&s->_q2);
}
}
QDataType StackBy2QueueTop(StackBy2Queue* s)
{
//取栈顶元素,看哪个队列里面有数据
assert(!StackBy2QueueEmpty(s));
if (!QueueEmpty(&s->_q1))
{
//因为入队列优先入倒第一个队列,所以去元素也优先去第一个队列中取
//如果第一个队列不为空,返回第一个队列的队尾
return QueueTail(&s->_q1);
}
else
return QueueTail(&s->_q2);
}
int StackBy2QueueSize(StackBy2Queue* s)
{
return QueueSize(&s->_q1) +QueueSize(&s->_q2);
}
int StackBy2QueueEmpty(StackBy2Queue* s)
{
return QueueEmpty(&s->_q1) && QueueEmpty(&s->_q2);
}
void Test()
{
StackBy2Queue s;
StackBy2QueueInit(&s);
StackBy2QueuePush(&s, 1);
StackBy2QueuePush(&s, 2);
StackBy2QueuePush(&s, 3);
StackBy2QueuePush(&s, 4);
StackBy2QueuePush(&s, 5);
printf("size=%d\n", StackBy2QueueSize(&s));
printf("top=%d\n", StackBy2QueueTop(&s));
printf("size=%d\n", StackBy2QueueSize(&s));
printf("top=%d\n", StackBy2QueueTop(&s));
StackBy2QueuePush(&s, 6);
StackBy2QueuePush(&s, 7);
printf("size=%d\n", StackBy2QueueSize(&s));
printf("top=%d\n", StackBy2QueueTop(&s));
StackBy2QueuePop(&s);
StackBy2QueuePop(&s);
printf("size=%d\n", StackBy2QueueSize(&s));
printf("top=%d\n", StackBy2QueueTop(&s));
}
int main()
{
Test();
return 0;
}
4、元素出栈、入栈顺序的合法性,如入栈的序列(1,2,3,4,5),出栈序列为(4,5,3,2,1)
int IsValidStack(int *In, int Insize, int* Out, int Outsize)
{
int Index = 0;
stack s;
int Outdex = 0;
if (Insize != Outsize)
return 0;
StackInit(&s);
while (Outdex < Outsize)
{
while (Stackempty(&s) || StackTop(&s) != Out[Outdex])
{
if (Index < Insize)
StackPush(&s, In[Index++]);
else
return 0;
}
StackPop(&s);
Outdex++;
}
return 1;
}
void test()
{
int In[] = { 1, 2, 3, 4, 5 };
int Out[] = { 4, 5, 3, 2, 1 };
if (!IsValidStack(In, 5, Out, 5))
printf("入栈出栈次序非法\n");
else
printf("没有问题\n");
}
int main()
{
test();
return 0;
}
或者:
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
int index=0;
if(pushV.size()==0)
return false;
stack<int> s;
for(int i=0;i<pushV.size();++i)
{
s.push(pushV[i]);
while(s.empty()==false&&s.top()==popV[index]&&index<popV.size())
{
s.pop();
index++;
}
}
if(s.empty())
return true;
else
return false;
}
};
5、一个数组实现两个栈(共享栈)
法一:一个数组从左到右的一半为栈s1,从右往左为栈s2,入栈是入哪个栈就从哪边开始
法二:把第一个栈的数据放到偶数位,把第二个栈的数据放到奇数位
#define MAX_SIZE 100
typedef struct ShareStack
{
int _array[MAX_SIZE];
int _top1;
int _top2;
}ShareStack;
void StackInit(ShareStack *s)
{
s->_top1 = 0;
s->_top2 = MAX_SIZE - 1;
}
void StackPush(ShareStack *s, int data,int which)
{
//入栈需要保持底层有空间,top2<top1则满了
if (s->_top2 < s->_top1)
{
return;
}
if (1 == which)
s->array[s->_top1++] = data;//往第一个栈里面放
else
s->array[s->_yop2++] = data;//往第二个栈里面放
}
void StackPop(ShareStack *s,int which)
{
if (Stackempty(s, which))
return;
if (1 == which)//第一个栈
s->_top1--;
else
s->_top2++;
}
int StackTop(ShareStack *s)
{
assert(!Stackempty(s,which));
if (1 == which)
return s->array[s->_top1 - 1];
else
return s->array[s->_top2 + 1];
}
int StackSize(ShareStack *s)
{
if (1 == which)
return s->_top1;
else
return MAX_SIZE-s->_top2-1;
}
int Stackempty(ShareStack *s, int which)
{
if (1 == which)
return s->_top1;
else
return MAX_SIZE-1==s->_top2;
}
(6)判断一棵二叉树最远的两个节点之间的距离(求二叉树的最大距离)
void FindMaxLen(Node *pRoot, int *maxLen)
{
int leftHeight = 0, rightHeight = 0;
if (NULL == pRoot)
return;
leftHeight = Height(pRoot->left);//左子树的高度
rightHeight = Height(pRoot->right);//右子树的高度
if (leftHeight + rightHeight > *maxLen)
*maxLen = leftHeight + rightHeight;
FindMaxLen(pRoot->left, maxLen);//在左子树中求最大的距离并更新
FindMaxLen(pRoot->right, maxLen);//在右子树中求最大的距离并更新
}
从上往下求高度,可能会重复,我们可以采用从下往上求得方式进行优化,如下
法2:
int GetMaxLen(Node* pRoot, int *maxLen)
{
int leftLen = 0, rightLen = 0;
if (NULL == pRoot)
return 0;
leftLen = GetMaxLen(pRoot->left, maxLen);
rightLen = GetMaxLen(pRoot->right, maxLen);
if (leftLen + rightLen > *maxLen)
*maxLen = leftLen + rightLen;
return leftLen > rightLen ? leftLen + 1 : rightLen + 1;
}
(7)将二叉搜索树转化成排序的双向链表。要求不创建任何新的节点,只能调整树中节点指针的指向
Node *BSTreeToDList(Node *pRoot)
{
Node *pPre = NULL;
Node *pHead = NULL;
if (NULL == pRoot)
return NULL;
//找链表的头
while (pHead->left)
//左子树存在
pHead = pHead->left;
_BSTreeToDList(pRoot,&pPre);//调整每一个节点左右指针域的指向
}
//按中序的序列调整左右指针的指向
void _BSTreeToDList(Node* pRoot,Node **pPre)
//在函数体里面要不断改变指针遍量pPre的指向,改变的结果要带出去,所以要传二级指针
{
if (NULL == pRoot)
return;
//先走左子树中节点左右指针域的指向
_BSTreeToDList(pRoot->left);
//调整根节点左指针域以及根节点的根的前驱节点都右指针域
//的指向(根节点的右指针域不能调整,不知道右指针域是什么。
//多家一个参数,标记前驱节点的位置
pRoot->left = pPre;
if (*pPre)
*pPre->right = pRoot;
*pPre = pRoot;//处理结束之后标记root
//调整右子树左右指针域的指向
_BSTreeToDList(pRoot->right);
}