栈和队列OJ题

1.栈实现队列

        用栈实现队列也就是使用栈来实现先进先出的效果,该操作用一个栈是无法完成的,我们考虑用两个栈,栈a用来模拟入队操作,栈b来模拟出队操作。例如以下把1,2,3,4入队(入栈),现在要做的是实现出栈顺序为1,2,3,4。

        需要模拟出队操作时只需要把栈a导到栈b中,然后在进行出栈就行,即出栈顺序就成了1,2,3,4而不是4,3,2,1,那么我们考虑把元素保持在栈b中,需要入队(入栈)的时候在把它导到栈a中,入完后再导回来。 这样就能实现先进先出的效果。

c语言代码演示 :

typedef int STDataType;
typedef struct Stack
{
	STDataType* _a; //栈空间
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;
void StackInit(Stack* ps)//初始化栈 
{
	assert(ps);
	ps->_a = NULL;
	ps->_top = ps->_capacity = 0;
}
void StackPush(Stack* ps, STDataType data)//入栈 
{
	assert(ps);
	if (ps->_top == ps->_capacity)
	{
		int dt = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		STDataType* pnew = (STDataType*)realloc(ps->_a, sizeof(STDataType) * dt);
		assert(pnew);
		ps->_a = pnew;
		ps->_capacity = dt;
	}
	ps->_a[ps->_top] = data;
	ps->_top++;
}
void StackPop(Stack* ps)//出栈 
{
	assert(ps);
	assert(ps->_top);
	ps->_top--;
} 
STDataType StackTop(Stack* ps)//获取栈顶元素
{
	assert(ps);
	assert(ps->_top);
	return ps->_a[ps->_top-1];
}
int StackSize(Stack* ps)//获取栈中有效元素个数 
{
	assert(ps);
	return ps->_top;
}
int StackEmpty(Stack* ps)//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
{
	assert(ps);
	return ps->_top == 0 ? 1 : 0;
}
void StackDestroy(Stack* ps)//销毁栈 
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_top = ps->_capacity = 0;
}
///
typedef struct {
    Stack* p1;
    Stack* p2;
} MyQueue;
MyQueue* myQueueCreate() {
    MyQueue* prt=(MyQueue*)malloc(sizeof(MyQueue));
    prt->p1=(Stack*)malloc(sizeof(Stack));
    prt->p2=(Stack*)malloc(sizeof(Stack));
    StackInit(prt->p1);
    StackInit(prt->p2);
    return prt;
}
void myQueuePush(MyQueue* obj, int x) {
    while(!StackEmpty(obj->p2))
    {
        StackPush(obj->p1,StackTop(obj->p2));
        StackPop(obj->p2);
    }
    StackPush(obj->p1,x);
    while(!StackEmpty(obj->p1))
    {
        StackPush(obj->p2,StackTop(obj->p1));
        StackPop(obj->p1);
    }
}
int myQueuePop(MyQueue* obj) {
    int ret=StackTop(obj->p2);
    StackPop(obj->p2);
    return ret;
}
int myQueuePeek(MyQueue* obj) {
    return StackTop(obj->p2);
}
bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(obj->p1)&&StackEmpty(obj->p2);
}
void myQueueFree(MyQueue* obj) {
    StackDestroy(obj->p1);
    StackDestroy(obj->p2);
    free(obj);
}

2.队列实现栈

        如果要用队列实现栈的话,使用一个队列是肯定不行的,队列结构是先进先出,栈结构是先进后出,所以我们要做的就是使用两个队列实现元素的先进后出的功能,要实现出栈操作我们只要,把左边栈的元素逐个导入右边队列中,直到剩下最后一个,再将它取出相当于出队操作。      

        此操作以后就会有一个队列空,在入栈操作的话我们需要把元素入到队列不为空的空间中, 要时刻保持有一个队列为空,让它用来做出栈的前几个元素的一个载体。也就是说每次入栈和出栈的时候都需要判断一下那个队列为空,那个不为空,再进行相应操作。 

c语言代码演示 :

#define QueueData int
typedef struct QueueNode
{
	QueueData val;
	struct QueueNode* next;
}QueueNode;
typedef struct
{
	QueueNode* phead;
	QueueNode* pend;
	int size;
}Queue;
void QueueInit(Queue* pQ)
{
	assert(pQ);
	pQ->pend = pQ->phead = NULL;
	pQ->size = 0;
}
void QueuePush(Queue* pQ, QueueData x)
{
	assert(pQ);
	QueueNode* pnew = (QueueNode*)malloc(sizeof(QueueNode));
	assert(pnew);
	pnew->val = x;
	pnew->next = NULL;
	if (pQ->size == 0)
	{
		pQ->pend = pQ->phead = pnew;
	}
	else
	{
		pQ->pend->next = pnew;
		pQ->pend = pnew;
	}
	pQ->size++;
}
QueueData QueueFront(Queue* pQ)
{

	assert(pQ);
	assert(pQ->size);
	return pQ->phead->val;
}
QueueData QueueBack(Queue* pQ)
{
	assert(pQ);
	assert(pQ->size);
	return pQ->pend->val;
}
void QueuePop(Queue* pQ)
{
	assert(pQ);
	QueueData ret = pQ->phead->val;
	if (pQ->size == 1)
	{
		free(pQ->phead);
		pQ->pend = pQ->phead = NULL;
	}
	else
	{
		QueueNode* pn = pQ->phead;
		pQ->phead = pQ->phead->next;
		free(pn);
	}
	pQ->size--;
}
int QueueSize(Queue* pQ)
{
	assert(pQ);
	return pQ->size;
}
bool QueueEmpty(Queue* pQ)//判空
{
	assert(pQ);
	return pQ->size==0;
}
void QueueDestroy(Queue* pQ)
{
	assert(pQ);
	while (pQ->phead)
	{
		QueueNode* pnext = pQ->phead->next;
		free(pQ->phead);
		pQ->phead=pnext;
	}
	pQ->pend = pQ->phead = NULL;
	pQ->size = 0;
}

typedef struct {
    Queue pQ1;
    Queue pQ2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* prt=(MyStack*)malloc(sizeof(MyStack));
    QueueInit(&prt->pQ1);
    QueueInit(&prt->pQ2);
    return prt;
}

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->pQ1))
        QueuePush(&obj->pQ1,x);
    else
        QueuePush(&obj->pQ2,x);
}

int myStackPop(MyStack* obj) {
    Queue* pnull=&obj->pQ1;
    Queue* pn=&obj->pQ2;
    if(QueueEmpty(pn))
    {
        pnull=&obj->pQ2;
        pn=&obj->pQ1;
    }
    while(pn->size-1!=0)
    {
        QueuePush(pnull,QueueFront(pn));
        QueuePop(pn);
    }
    int ret=QueueFront(pn);
    QueuePop(pn);
    return ret;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->pQ1))
        return QueueBack(&obj->pQ1);
    else
        return QueueBack(&obj->pQ2);
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->pQ1)&&QueueEmpty(&obj->pQ2);
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->pQ1);
    QueueDestroy(&obj->pQ2);
    free(obj);
    obj=NULL;
}

3.循环队列

        对于循环队列的实现我们可以使用顺序表或链表,不过使用链表比较复杂,更为推荐使用顺序表,此题我们就以顺序表来解决。 

        我们使用Head来储存队头下标,使用End来储存队尾元素的下一个空间的下标,那么当队列为空的时候,Head和End就指向同一个位置,等队满之后,End又绕回到头。如下:

 

        这样看起来一个循环队列很简单的就能写出来,不过这里还有一个显而易见的问题,就是如何判断队列是否空?如何判断队列是否满?这里可千万不要认为Head和End指向同一个位置就是满或空,或者认为Head和End同时指向下标为0的位置就是空。我们来看把上面队列元素都出队会怎样:

        在这里我们可以观察到无论是队列满还是空Head和End都是指向同一个位置,所以此时我们是无法判断队列是满是空的, 为了解决之这个问题现在有两个方案

        方案1:添加一个变量size来储存队列的长度,当有元素入队size++,有元素出队size--。

        方案2:添加一个新的空间而这个新的空间并不用来储存有效元素,只是为了当栈满的时候不让End指向Head可以用来区别于End和Head指向同一位置的时候栈为空的情况,比如原来队列需要的是k个空间,那么我们可以创建k+1个空间,那么我们就可以用Head和End相等来表示栈空Head等于End+1来表示栈满,然后需要处理一下End等于k这个特殊情况,如下两种栈满的情况:

        处理一下End等于k这个特殊情况,我们可以用if语句或者用取模运算,如:(End+1)%(k+1) 

typedef struct {
    int* arr;
    int head;
    int end;
    int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* prt=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    prt->arr=(int*)malloc(sizeof(int)*(k+1));
    prt->head=prt->end=0;
    prt->k=k;
    return prt;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->end!=obj->k)
        return obj->end+1==obj->head;
    else
        return obj->head==0;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->head==obj->end;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    else
    {
        obj->arr[obj->end]=value;
        obj->end++;
        if(obj->end==obj->k+1)
            obj->end=0;
        return true;
    }
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->head++;
    obj->head%=obj->k+1;
    return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int ret=obj->arr[obj->head];
    return ret;
}
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    if(obj->end==0)
        return obj->arr[obj->k];
    return obj->arr[obj->end-1];
}
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

  • 86
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 72
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值