栈和队列的面试题

申明一下在开头先:下面代码的实现有用到栈和队列的操作代码,。

栈的代码链接:https://blog.csdn.net/ijn842/article/details/80274340

队列的代码链接:https://blog.csdn.net/ijn842/article/details/80314060


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

假设要入队列的元素为 1 、2、3、4、5,而队列的底层实现为两个栈,我们都知道队列的规则为先进先出(即在队尾进行入元素的操作,而在队头进行出元素的操作),而栈的规则为先进后出(或者是后进先出,一样的),两个栈想要实现一个队列就必须指定一个栈来先进行入队列的操作,但是因为先进去的元素在栈底,出队列的时候就不能是它先出,所以将除栈底以外的元素保存到另一个栈中,这时栈底的元素已成为栈顶,就可以出栈也就是出队列了。这样就实现了队列的进出了



下面是代码

QueueBy2StackInterview.h

#include "Stack.h"

typedef struct QueueBy2Stack
{
	struct Stack s1;
	struct Stack s2;
}QueueBy2Stack,*PQueueBy2Stack;

//1.初始化队列
void QueueBy2StackInit(PQueueBy2Stack q);

//2.入队列
void QueueBy2StackPush(PQueueBy2Stack q,DataType data);

//3.出队列
void QueueBy2StackPop(PQueueBy2Stack q);

//4.判空
int QueueBy2StackEmpty(PQueueBy2Stack q);

//5.获取队头元素
DataType QueueBy2StackFront(PQueueBy2Stack q);

//6.获取队尾元素
DataType QueueBy2StackRear(PQueueBy2Stack q);

//7.队列长度
int QueueBy2StackSize(PQueueBy2Stack q);

//8.打印队列
void QueueBy2StackPrint(PQueueBy2Stack q);

QueueBy2StackInterview.c

#define _CRT_SECURE_NO_WARNING 1


#include "QueueAndStackInterview.h"

//1.初始化队列
void QueueBy2StackInit(PQueueBy2Stack q)
{
	assert(q);
	StackInit(&q->s1);
	StackInit(&q->s2);
}

//2.入队列
void QueueBy2StackPush(PQueueBy2Stack q,DataType data)
{
	assert(q);
	if(MAX_SIZE == q->s1._top)
		return;
	if(!StackEmpty(&q->s2))
	{
		while(StackSize(&q->s1))
		{
			StackPush(&q->s1,StackTop(&q->s2));
			StackPop(&q->s2);
		}
	}
	else
		StackPush(&q->s1,data);
}

//3.出队列
void QueueBy2StackPop(PQueueBy2Stack q)
{
	assert(q);
	if(QueueBy2StackEmpty(q))
		return;

	//出完一个元素后,将栈s2里的元素放回栈s1里(因为指定了进出队列都在栈s1里)
	if(!StackEmpty(&q->s2))
	{
		while(StackSize(&q->s2))
		{
			StackPush(&q->s1,StackTop(&q->s2));
			StackPop(&q->s2);
		}
	}
	//将栈s1里的元素放到栈s2中,直到s1里剩一个元素为止,将该元素出栈即可
	while(StackSize(&q->s1) > 1)
	{
		StackPush(&q->s2,StackTop(&q->s1));
		StackPop(&q->s1);
	}
	StackPop(&q->s1);
}

//4.判空
int QueueBy2StackEmpty(PQueueBy2Stack q)
{
	assert(q);
	if(StackEmpty(&q->s1)&&StackEmpty(&q->s2))
		return 1;
	return 0;
}

//5.获取队头元素
DataType QueueBy2StackFront(PQueueBy2Stack q)
{
	assert(q);
	if(!QueueBy2StackEmpty(q))
	{
		//将栈s1里的全部元素放到s2里
		while(StackSize(&q->s1))
		{
			StackPush(&q->s2,StackTop(&q->s1));
			StackPop(&q->s1);
		}
	}
	return StackTop(&q->s2);
}

//6.获取队尾元素
DataType QueueBy2StackRear(PQueueBy2Stack q)
{
	assert(q);
	if(!StackEmpty(&q->s2))
	{
		if(!StackEmpty(&q->s2))
		//将栈s2里的全部元素放到s1里
		{
			while(StackSize(&q->s2))
			{
				StackPush(&q->s1,StackTop(&q->s2));
				StackPop(&q->s2);
			}
		}
	}
	return StackTop(&q->s1);
}

//7.队列长度
int QueueBy2StackSize(PQueueBy2Stack q)
{
	assert(q);
	if(QueueBy2StackEmpty(q))
		return 0;
	if(!StackEmpty(&q->s2))
	{
		while(StackSize(&q->s2))
		{
			StackPush(&q->s1,StackTop(&q->s2));
			StackPop(&q->s2);
		}
	}
	return StackSize(&q->s1);
}

//8.打印队列
void QueueBy2StackPrint(PQueueBy2Stack q)
{
	int i = 0;
	assert(q);

	if(QueueBy2StackEmpty(q))
		return ;

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

	for( ; i < StackSize(&q->s1) ;i++)
	{
		printf("%d--->", q->s1._array[i]);
	}
	printf("NULL\n");
}

test.c

#include "QueueAndStackInterview.h"

int main()
{
	QueueBy2Stack q;
	QueueBy2StackInit(&q);
	QueueBy2StackPush(&q,1);
	QueueBy2StackPush(&q,2);
	QueueBy2StackPush(&q,3);
	QueueBy2StackPush(&q,4);
	QueueBy2StackPush(&q,5);
	QueueBy2StackPush(&q,6);
	QueueBy2StackPush(&q,7);
	QueueBy2StackPrint(&q);
	printf("front is:%d\n",QueueBy2StackFront(&q));
	printf("rear is:%d\n",QueueBy2StackRear(&q));
	printf("size is:%d\n",QueueBy2StackSize(&q));

	QueueBy2StackPop(&q);
	QueueBy2StackPop(&q);
	QueueBy2StackPrint(&q); 
	printf("front is:%d\n",QueueBy2StackFront(&q));
	printf("rear is:%d\n",QueueBy2StackRear(&q));
	printf("size is:%d\n",QueueBy2StackSize(&q));

        return 0;
}

2.使用两个队列实现栈

栈的实现底层用两个队列  
队列的基本特性是先进先出 栈的基本特性是先进后出
元素进队列的时候,比如{1,2,3,4,5,},进队列的完毕是  (从队尾开始) {5,4,3,2,1} {1,2,,3,4,5}进栈完毕后的序列也是{5,4,3,2,1},所以说用队列实现了进栈

但是问题来了,由于栈和队列的出特性并不一致,那么怎样实现呢

就拿{1,2,3,4,5}继续来说,入队列完毕后队尾是5而在栈中它便是栈顶元素,不能直接出栈,所以此时我们另一个队列便派上了用场,可以让队头元素1保存入队列到第二个队列里面,后面的2,3,4进行一样的操作,最后第一个队列只剩下队尾元素同时也是队头元素5出队列了也就是实现了出栈,只不过此时队列2里面的元素序列为{4,3,2,1}和队列1未进行出栈操作前是一样的(当然了少了一个元素5而已),所以并不需要重新把元素搬回队列1,重复上述和队列1一样的操作就可以实现出栈了。

        


QueueBy2StackInterview.h

typedef struct StackBy2Queue
{
	struct SQueue q1;
	struct SQueue q2;
}StackBy2Queue,*PStackBy2Queue;


//1.初始化栈
void StackBy2QueueInit(PStackBy2Queue s);


//2.入栈
void StackBy2QueuePush(PStackBy2Queue s,DataType data);


//3.出栈
void StackBy2QueuePop(PStackBy2Queue s);


//4.获取栈顶元素
DataType StackBy2QueueTop(PStackBy2Queue s);


//5.查看栈的元素个数
int StackBy2QueueSize(PStackBy2Queue s);


//6.判空
int StackBy2QueueEmpty(PStackBy2Queue s);

QueueBy2StackInterview.c

//1.初始化栈
void StackBy2QueueInit(PStackBy2Queue s)
{
	assert(s);
	SQueueInit(&s->q1);
	SQueueInit(&s->q2);
}

//2.入栈
void StackBy2QueuePush(PStackBy2Queue s,DataType data)
{
	assert(s);
	if(SQueueEmpty(&s->q1) && SQueueEmpty(&s->q2))
		SQueuePush(&s->q1,data);
	else if(!SQueueEmpty(&s->q1))
		SQueuePush(&s->q1,data);
	else
		SQueuePush(&s->q2,data);
}

//3.出栈
void StackBy2QueuePop(PStackBy2Queue s)
{
	assert(s);
	if(!StackBy2QueueEmpty(s))
	{
		if(!SQueueEmpty(&s->q1))
		{
			while(SQueueSize(&s->q1) > 1)
			{
				SQueuePush(&s->q2,SQueueFrontData(&s->q1));
				SQueuePop(&s->q1);
			}
			SQueuePop(&s->q1);
		}
		else
		{
			while(SQueueSize(&s->q2) > 1)
			{
				SQueuePush(&s->q1,SQueueFrontData(&s->q2));
				SQueuePop(&s->q2);
			}
			SQueuePop(&s->q2);
		}
	}

}

//4.获取栈顶元素
DataType StackBy2QueueTop(PStackBy2Queue s)
{
	assert(s);
	if(StackBy2QueueEmpty(s))
		return 0;
	
	if(!SQueueEmpty(&s->q1))
		return SQueueRearData(&s->q1);

	else
		return SQueueRearData(&s->q1);
}

//5.查看栈的元素个数
int StackBy2QueueSize(PStackBy2Queue s)
{
	assert(s);
	if(StackBy2QueueEmpty(s))
		return 0;
	if(!SQueueEmpty(&s->q1))
		return SQueueSize(&s->q1);
	return SQueueSize(&s->q2);
}

//6.判空
int StackBy2QueueEmpty(PStackBy2Queue s)
{
	if(SQueueEmpty(&s->q1) &&SQueueEmpty(&s->q2))
		return 1;
	return 0;
}
#endif

test.c

StackBy2Queue s;
	StackBy2QueueInit(&s);
	StackBy2QueuePush(&s,1);
	StackBy2QueuePush(&s,2);
	StackBy2QueuePush(&s,3);
	StackBy2QueuePush(&s,4);
	StackBy2QueuePush(&s,5);
	StackBy2QueuePush(&s,6);
	StackBy2QueuePush(&s,7);
	StackBy2QueuePush(&s,8);
	printf("top is:%d\n",StackBy2QueueTop(&s));
	printf("size is:%d\n",StackBy2QueueSize(&s));

	StackBy2QueuePop(&s);
	StackBy2QueuePop(&s);
	printf("top is:%d\n",StackBy2QueueTop(&s));
	printf("size is:%d\n",StackBy2QueueSize(&s));

3.实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)    

          我们都知道对于一个栈来说入栈和出栈操作每次都是一个元素,时间复杂度便是O(1),但是对于获得最小值便不一定了,因为有可能最小值不一定在栈顶位置,所以是不能直接对其进行操作的。

          故此我们可以用一个结构体在里面封装元素data和最小值mindata,有什么用呢?      

        相当于我们每次入栈的时候都是入这个结构体,即有元素和最小值元素两个数值均入栈,当第一元素入栈的时候将最小值也标记为该元素的值,当第二个元素入栈的时候,用其和第一个最小值比较,如果小于便将第二个元素的最小值置为该元素的值,后面的元素入栈的最小值依次进行该操作,最后当我们取栈顶元素,同时可以取到栈顶元素的值和最小元素的值,时间复杂度均为O(1)

    

QueueBy2StackInterview.h

//1.实现一个栈,要求实现Push(入栈)、Pop(出栈)、
//Min(返回最小值)的时间复杂度为O(1)

//1.初始化栈
void MinStackInit(Stack* s);

//2.入栈
void MinStackPush(Stack* s,ElemType data);

//3.出栈
void MinStackPop(Stack* s);

//4.判空
int MinStackEmpty(Stack* s);

//5.获取栈顶元素
ElemType MinStackTop(Stack* s);

//6.获取栈的长度
int MinStackSize(Stack* s);

//7.查看最小元素
ElemType MinStackminData(Stack* s);

QueueBy2StackInterview.c

//1.初始化栈void MinStackInit(Stack* s)

{
	assert(s);
	StackInit(s);
}

//2.入栈
void MinStackPush(Stack* s,ElemType data)
{
	DataType elem;
	assert(s);
	if(StackEmpty(s))
	{
		elem._data = elem._mindata = data;
		StackPush(s,elem);
	}
	else
	{
		elem = StackTop(s);
		if(elem._mindata > data)
			elem._mindata = data;
		elem._data = data;
		StackPush(s,elem);
	}

	
}

//3.出栈
void MinStackPop(Stack* s)
{
	assert(s);
	if(StackEmpty(s))
		return;
	s->_top--;
}

//4.判空
int MinStackEmpty(Stack* s)
{
	assert(s);
	return s->_top == 0;
}

//5.获取栈顶元素
ElemType MinStackTop(Stack* s)
{
	assert(!MinStackEmpty(s));
	return s->_array[s->_top]._data;
}


//6.获取栈的长度
int MinStackSize(Stack* s)
{
	assert(s);
	return s->_top;
}


//7.查看最小元素
ElemType MinStackminData(Stack* s)
{
	assert(!MinStackEmpty(s));
	return s->_array[s->_top]._mindata;
}

4.一个数组实现两个栈


QueueBy2StackInterview.h

#include <stdio.h>
#include <assert.h>
#define MAX_SIZE 10

typedef int DataType;

typedef struct Stack
{
	DataType _array[MAX_SIZE];
	int _top1;
	int _top2;
}Stack;

//1.栈的初始化
void ShareStackInit(Stack* s);

//2.入栈
void ShareStackPush(Stack* s, DataType data, int which);

//3.出栈
void ShareStackPop(Stack* s, int which);

//4.判空
int ShareStackEmpty(Stack* s, int which);

//5.查看长度
int ShareStackSize(Stack* s, int which);

//6.查看栈顶元素
DataType ShareStackTop(Stack* s,int which);

QueueBy2StackInterview.c

void ShareStackInit(Stack* s)
{
	assert(s);
	s->_top1 = 0;
	s->_top2 = MAX_SIZE-1;//栈2的栈顶从数组下标的最后一个开始
}

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

	if(s->_top1 > s->_top2)
	{
		printf("栈已满!!!\n");
		return;
	}
	if(1 == which)
		s->_array[s->_top1++] = data;
	else
		s->_array[s->_top2--] = data;
}

//3.出栈
void ShareStackPop(Stack* s, int which)
{
	assert(s);
	assert(1 == which || 2 == which);

	if(1 == which)
	{
		if(0 == s->_top1)
			return;
		s->_top1--;
	}
	else
	{
		if(MAX_SIZE-1 == s->_top2)//栈顶指针指到了栈底,此时说明栈2为空
			return;
		s->_top2++;
	}
}

//4.判空
int ShareStackEmpty(Stack* s, int which)
{
	assert(s);
	assert(1 == which || 2 == which);
	if(1 == which)
	{
		if(0== s->_top1)
			return 1;
	}
	else
	{
		if(MAX_SIZE-1 == s->_top2)
			return 1;
	}
	return 0;
}

//5.查看长度
int ShareStackSize(Stack* s, int which)
{
	assert(s);
	assert(1 == which || 2 == which);

	return 1 == which ? s->_top1 : MAX_SIZE-1-s->_top2;
}

//6.查看栈顶元素
DataType ShareStackTop(Stack* s,int which)
{
	assert(s);
	assert(1 == which || 2 == which);
	if(1 == which)
		return s->_array[s->_top1-1];
	else
		return s->_array[s->_top2-1];
}

test.c

int main()
{
	Stack s;
	ShareStackInit(&s);
	ShareStackPush(&s,1,1);
	ShareStackPush(&s,2,1);
	ShareStackPush(&s,3,1);
	ShareStackPush(&s,4,1);
	printf("size1 is:%d\n",ShareStackSize(&s,1));
	//printf("top1 is:%d\n",ShareStackTop(&s,2));
	printf("s->_top1 empty is:%d\n",ShareStackEmpty(&s,1));

	ShareStackPop(&s,1);
	printf("size1 is:%d\n",ShareStackSize(&s,1));
	//printf("top1 is:%d\n",ShareStackTop(&s,2));
	printf("s->_top1 empty is:%d\n",ShareStackEmpty(&s,1));

	ShareStackInit(&s);
	ShareStackPush(&s,5,2);
	ShareStackPush(&s,6,2);
	ShareStackPush(&s,7,2);
	ShareStackPush(&s,8,2);
	printf("size2 is:%d\n",ShareStackSize(&s,2));
	//printf("top2 is:%d\n",ShareStackTop(&s,2));
	printf("s->_top2 empty is:%d\n",ShareStackEmpty(&s,2));

	ShareStackPop(&s,2);
	printf("size2 is:%d\n",ShareStackSize(&s,2));
	//printf("top2 is:%d\n",ShareStackTop(&s,2));
	printf("s->_top2 empty is:%d\n",ShareStackEmpty(&s,2));
	return 0;
}

5.元素出栈、入栈顺序的合法性。如入栈序列{1,2,3,4,5},出栈序列{4,5,3,2,1}

我们用index来标记入栈数组下标,用outdex来标记出栈序列下标,当入栈的元素等于outdex下标所标记的元素时,就让该元素出栈,两个下标继续往后走,如果不相等,就让入栈序列继续入栈(index++),直到有index所指元素等于outdex所指元素相等时,该元素才出栈,outdex才继续玩后走,重复循环上述步骤即可。



源代码

int InOutIsValid(int* Inorder,int InSize,int* Outorder,int OutSize)
{
	int Index = 0;//入栈数组下标
	int Outdex = 0;//出栈数组下标

	Stack s;
	StackInit(&s);

	while(Outdex<OutSize)
	{
		while(StackEmpty(&s) || StackTop(&s) != Outorder[Outdex])
		{
			if(Index < InSize)
			{
				StackPush(&s,Inorder[Index++]);
			}
			else
				return 0;
		}
		StackPop(&s);
		Outdex++;
	}
	return 1;
}

测试代码

#include "QueueAndStackInterview.h"

int main()
{
	int Inorder[] = {1,2,3,4,5};
	int Outorder[] = {4,5,3,2,1};
	int InSize = sizeof(Inorder)/sizeof(Inorder[0]);
	int OutSize = sizeof(Outorder) / sizeof(Outorder[0]);
	int ret = InOutIsValid(Inorder, InSize,Outorder,OutSize);
	printf("%d\n",ret);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/ijn842/article/details/80274446