您的位置:首页 > 职场人生

关于栈和队列的面试题

2018-03-28 23:15 155 查看
1.实现一个栈,要求实现Push,Pop ,Min(返回最小值)的时间复杂度为O(1)

方法一:

解题思路:首先我们在之前封装的栈结构外面再封装一层,将其封装为一个最小栈, 与之前不同的是,我们在栈中存放的是一个结构体,这个结构体中有两个成员, 一个是数据本身的值,另一个为栈内所有存放元素中的最小值,这样即可实现压栈,出栈,取最小值操作都为O(1)

代码如下:

//用当前元素值和栈内最小元素值封装一个结构体
typedef struct Elem
{
int _data;//元素数值本身
int _minData;//栈中所有元素的最小值
}Elem;

//最小栈
typedef struct MinStack
{
Stack _s;
}MinStack;

//初始化最小栈
void InitMinStack(MinStack *s)
{
StackInit(&s->_s);
}

//压栈
void MinStackPush(MinStack *s, int data)
{
assert(s);

//构造元素
Elem cur;
cur._data = data;
cur._minData = data;

//若栈为空,直接将该元素压栈
if (StackEmpty(&s->_s))
StackPuch(&s->_s, cur);

//栈不为空时,用栈顶元素中的最小值与当前元素进行
4000
比较
//若栈顶元素中的最小值小于当前元素值,则用栈顶的最小值
//来更新当前元素中的最小值
else
{
Elem top = StackTop(&s->_s);
if (cur._minData > top._minData)
cur._minData = top._minData;

StackPuch(&s->_s, cur);
}
}

//出栈
void MinStackPop(MinStack *s)
{
assert(s);
if (StackEmpty(&s->_s))
return;

StackPop(&s->_s);
}

//取栈顶
int MinStackTop(MinStack *s)
{
Elem top;

top = StackTop(&s->_s);
return top._minData;
}


上述方法存在缺陷,每次压栈需压入一个结构体两个数据,有些情况下,每次压入的最小值都是相同的,重复操作,因此我们采用另一种方式。

方法二:

思路:封装一个结构,其中包括两个栈,一个栈保存所有的数据,另一个栈保存最小值, 每次进来一个值都将其压入保存数据的栈中,若该数据比最小值栈的栈顶元素小,也将该值压入最小值栈中,否则不操作。出栈时,每次从数据栈中弹出一个元素,若该元素与最小值栈的栈顶元素相同时,最小值栈也要进行出栈操作,否则不出元素,这种方式 获取最小值更为简单,直接取最小值栈的栈顶元素,他们的时间复杂度都为O(1)。

代码如下:

//将这两个栈封装成一个结构体
typedef struct MinStack
{
Stack _data;
Stack _minData;
}MinStack;

//初始化两个栈
void InitMinStack(MinStack *s)
{
assert(s);
StackInit(&s->_data);
StackInit(&s->_minData);
}

//压栈
void MinStackPush(MinStack *s, DataType data)
{
assert(s);

StackPuch(&s->_data, data);

if (StackEmpty(&s->_minData) || data < StackTop(&s->_minData))
{
StackPuch(&s->_minData,data);
}
}

//出栈
void MinStackPop(MinStack *s)
{
DataType top = StackTop(&s->_data);
if ( top == StackTop(&s->_minData))
{
StackPop(&s->_minData);
}
StackPop(&s->_data);
}

//获取栈顶
DataType MinStackTop(MinStack *s)
{
return StackTop(&s->_minData);
}


注意:若连续向栈中压入相同的最小数据时,最小栈只能进行一次压栈,而出栈时,最小栈就会将该最小值弹出来,从而导致错误,因此要使用这种方式,我们需要对最小栈中的每个元素的个数进行计数,当其计数为0时再出栈。代码有待完善。

2.使用两个栈实现一个队列

解题思路:

其中一号栈用来入队列,二号栈用来出队列

入队列:直接对一号栈进行压栈操作

出队列:对二号栈进行出栈操作,当二号栈中没有元素时,将一号栈的元素倒入二号栈中

取队头:获取二号栈的栈顶元素,当二号栈中没有元素时,将一号栈的元素倒入二号栈中

取队尾:获取一号栈的栈顶元素,当一号栈中没有元素时,将二号栈的元素重新倒到二号栈中

代码如下:

//将两个栈封装成一个队列
typedef struct QueueByStack
{
Stack s1;
Stack s2;
}QueueByStack;

//初始化该队列
void QueueByStackInit(QueueByStack *q)
{
assert(q);
StackInit(&q->s1);
StackInit(&q->s2);
}

//入队列
void QueueByStackPush(QueueByStack *q,DataType data)
{
assert(q);
StackPuch(&q->s1, data);
}

//队列判空
int QueueByStackEmpty(QueueByStack *q)
{
assert(q);
return StackEmpty(&q->s1) && StackEmpty(&q->s2);
}

//出队列
void QueueByStackPop(QueueByStack *q)
{
assert(q);
if (QueueByStackEmpty(q))
return;

if (StackEmpty(&q->s2))
{
//倒元素
while (!StackEmpty(&q->s1))
{
StackPuch(&q->s2, StackTop(&q->s1));
StackPop(&q->s1);
}
}
StackPop(&q->s2);
}

//获取队头
DataType QueueByStackFront(QueueByStack *q)
{
assert(q);

if (StackEmpty(&q->s2))
{
//倒元素
while (!StackEmpty(&q->s1))
{
StackPuch(&q->s2, StackTop(&q->s1));
StackPop(&q->s1);
}
}
return StackTop(&q->s2);
}

//获取队尾
DataType QueueByStackBack(QueueByStack *q)
{
assert(q);

if (StackEmpty(&q->s1))
{
while (!StackEmpty(&q->s2))
{
StackPuch(&q->s1, StackTop(&q->s2));
StackPop(&q->s2);
}
}
return StackTop(&q->s1);
}

//求队列中元素个数
int QueueByStackSize(QueueByStack *q)
{
assert(q);
return StackSize(&q->s1) + StackSize(&q->s2);
}


3.通过两个队列实现一个栈

解题思路:

入栈:哪个队列不空就向哪个队列进行入队列操作

出栈:从不空的队列向另一空队列中倒元素,直至该队列中剩余一个元素,将该元素出队列

取栈顶:即获取非空队列的队尾元素

代码如下:

//将两个队列封装为一个栈
typedef struct StackByQueue
{
Queue q1;
Queue q2;
}StackByQueue;

//初始化两队列
void StackByQueueInit(StackByQueue *s)
{
assert(s);
InitQueue(&s->q1);
InitQueue(&s->q2);
}

//入栈
void StackByQueuePush(StackByQueue *s,DataType data)
{
assert(s);
if (!EmptyQueue(&s->q1))
QueuePush(&s->q1, data);
else
QueuePush(&s->q2,data);
}

//对栈判空
int StackByQueueEmpty(StackByQueue *s)
{
assert(s);
return EmptyQueue(&s->q1) && EmptyQueue(&s->q2);
}

//出栈
void StackByQueuePop(StackByQueue *s)
{
assert(s);
if (StackByQueueEmpty(s))
return;

if (!EmptyQueue(&s->q1))
{
while (Size(&s->q1) > 1)
{
QueuePush(&s->q2, Front(&s->q1));
QueuePop(&s->q1);
}
QueuePop(&s->q1);
}
else
{
while (Size(&s->q2) > 1)
{
QueuePush(&s->q1, Front(&s->q2));
QueuePop(&s->q2);
}
QueuePop(&s->q2);
}
}

//取栈顶
DataType StackByQueueTop(StackByQueue *s)
{
assert(s);
if (!EmptyQueue(&s->q1))
return back(&s->q1);
else
return back(&s->q2);
}

//获取栈元素个数
int StackByQueueSize(StackByQueue *s)
{
assert(s);
return Size(&s->q1) + Size(&s->q2);
}


4.判断元素出栈、入栈顺序的合法性。如入栈的序列(1,2,3,4,5),出栈序列为(4,5,3,2,1)

给出代码:

int TestStackInAndOutValid(int *In, int InSize, int *Out, int OutSize)
{
Stack s;
int InIdx = 0;//入栈序列索引
int OutIdx = 0;//出栈序列索引

//若入栈序列与出栈序列元素个数不相等,必定非法 直接返回0
if (InSize != OutSize)
return 0;

StackInit(&s);

//出栈索引未越界即出栈序列中元素未走完时,循环一直继续
while (OutIdx < OutSize)
{
//若栈为空或者栈顶元素不等于出栈序列中指定索引位置的元素,一直进行入栈
while (StackEmpty(&s) || StackTop(&s) != Out[OutIdx])
{
//当入栈索引未越界时再入栈,否则说明出栈序列非法
if (InIdx < InSize)
StackPuch(&s, In[InIdx++]); //入栈后,入栈索引向后走一步
else
return 0;
}

//此时栈顶元素等于出栈索引指定元素,进行chuzhan
StackPop(&s);
OutIdx++;//出栈索引向后走一步
}

//此时出栈序列中元素已全部出栈,说明序列合法
return 1;
}


5.一个数组实现两个栈(共享栈)

方法一:以数组的两端分别为两个栈的栈底,入栈时两个栈向中间靠拢

方法二:以数组下标为积数的空间作为一号栈的空间,偶数下标空间作为二号栈的空间 每次入栈,栈顶向后走两步

相比之下,方法一比方法二要好些,可以重复利用这段空间。

#define MAX_SIZE 10

//在一个数组上搭建共享栈
typedef struct SharedStack
{
int _array[MAX_SIZE];
int _top1;//一号栈的栈顶
int _top2;//二号栈的栈顶
}SharedStack;

//初始化共享栈
void SharedStackInit(SharedStack *s)
{
assert(s);
s->_top1 = 0;
s->_top2 = MAX_SIZE - 1;
}

//入栈
void SharedStackPush(SharedStack *s, DataType data,int which)
{
assert(s);
assert(1 == which || 2 == which);

if (s->_top1 > s->_top2)//共享栈已满
return;

if (1 == which)
s->_array[s->_top1++] = data;//向1号栈中入元素
else
s->_array[s->_top2--] = data;//向2号栈中入元素

}

//判断一号栈或二号栈是否为空
int SharedStackEmpty(SharedStack *s, int which)
{
assert(s);
assert(1 == which || 2 == which);

if (1 == which)
return 0 == s->_top1;
else
return MAX_SIZE-1 == s->_top2;
}

//出栈
void SharedStackPop(SharedStack *s, int which)
{
assert(s);
assert(1 == which || 2 == which);

if (SharedStackEmpty(s, which))
return;

if (1 == which)
s->_top1--;
else
s->_top2++;
}

//获取一号栈或二号栈的栈顶
DataType SharedStackTop(SharedStack *s, int which)
{
assert(s);
assert(1 == which || 2 == which);
assert(!SharedStackEmpty(s, which));

if (1 == which)
return s->_array[s->_top1 - 1];
else
return s->_array[s->_top2 + 1];
}

//获取一号栈或二号栈的元素个数
int SharedStackSize(SharedStack *s, int which)
{
assert(s);
assert(1 == which || 2 == which);

if (1 == which)
return s->_top1;
else
return MAX_SIZE - s->_top2 - 1;
}


测试共享栈:

void TestSharedStack()
{
SharedStack s;
SharedStackInit(&s);
SharedStackPush(&s, 1, 1);
SharedStackPush(&s, 3, 1);
SharedStackPush(&s, 5, 1);
SharedStackPush(&s, 7, 1);
SharedStackPush(&s, 9, 1);
SharedStackPush(&s, 2, 2);
SharedStackPush(&s, 4, 2);
SharedStackPush(&s, 6, 2);
SharedStackPush(&s, 8, 2);
SharedStackPush(&s, 10, 2);
printf("top1=%d\n", SharedStackTop(&s, 1));
printf("size1=%d\n", SharedStackSize(&s, 1));

printf("top2=%d\n", SharedStackTop(&s, 2));
printf("size1=%d\n", SharedStackSize(&s, 2));

SharedStackPop(&s, 1);
SharedStackPop(&s, 2);
printf("top1=%d\n", SharedStackTop(&s, 1));
printf("size1=%d\n", SharedStackSize(&s, 1));

printf("top2=%d\n", SharedStackTop(&s, 2));
printf("size1=%d\n", SharedStackSize(&s, 2));
}


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: