数据结构-栈与队列的相互关系以及实现方式

目录

前言

一、用栈实现队列

1.题目理解

2.思路

3.代码编写

二、用队列实现栈

1.题目理解

2.思路

3.代码编写

总结


前言

上一章我们实现栈和队列,也提到了栈与队列是存在相互的关系的,那是什么呢我们可以看看力扣的两到题目:

 232. 用栈实现队列

 225. 用队列实现栈

我们可以发现栈居然能实现队列!!!相反队列也是可以实现栈的,那接下来我们就实现以下两个功能吧,当然还有循环队列我们待会也会提到。 


一、用栈实现队列

1.题目理解

简单来说我们需要用两个栈利用先进后出的原理来实现队列的功能。

2.思路

首先假设我们在一个栈中入栈了4个元素,要出栈也是最上面的元素先出,显然不能达到队列的先进先出的要求的,那么什么情况可以让他们数字倒过来,以至于达成我们想要的效果呢?其实我们可以多创建一个栈,将开始进栈的元素出栈到新栈里那就可以将元素倒过来了。

那么接下来有两种思路实现下一步,先说第一种,现在我们将s1的元素转移到s2里,这是为了实现栈底元素先出栈想出的办法,那么 s1里就空了,我们可以为了数据进入数据顺序不变,可以将s2的元素倒回s1里,这种方法也是可以的,但是进行插入数据的话时间复杂度是O(2n),虽说最后简化为O(n),但是两次循环不太好,那有其他的解决办法吗,当然有那么接下来就说说思路二吧。

思路二的话也很好理解,当我们数据都在s1入栈时,那么s2就用来出元栈用的,那么我们需要出栈就在s2出,一旦s2为空时,就将s1的元素全部倒到s2中,这样的话我们只会用一次循环即可,在时间复杂度上是比较优的。

 

我们思路有那就开始实现,这边小编就用方法一来实现以上的功能吧,有兴趣的同学也可以自己尝试用思路二来实现的。

3.代码编写

typedef int SLDataType;

typedef struct Stack {
	SLDataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;

//初始化栈
void StackInit(Stack* ps);  
//入栈
void StackPush(Stack* ps, SLDataType x);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
SLDataType StackTop(Stack* ps);
//栈中有效数据范围
int StackSize(Stack* ps);
//检测栈是否为空
bool StackEmpty(Stack* ps);
//栈销毁
void StackDestory(Stack* ps);


void StackInit(Stack* ps) {
	assert(ps);
	ps->a = NULL;
	ps->top = -1;
	ps->capacity = 0;
}

void StackPush(Stack* ps, SLDataType x) {
	assert(ps);
	if (ps->top + 1 == ps->capacity) {//增容
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* p = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
		if (p == NULL) {
			perror("realloc p");
			return;
		}
		ps->a = p;
		ps->capacity = newcapacity;
	}
	ps->a[++ps->top] = x;
}

void StackPop(Stack* ps) {
	assert(ps);
	assert(ps->top > -1);
	ps->top--;
}

SLDataType StackTop(Stack* ps) {
	assert(ps);
	assert(ps->top > -1);
	return ps->a[ps->top];
}

int StackSize(Stack* ps) {
	assert(ps);
	return ps->top + 1;
}

bool StackEmpty(Stack* ps) {
	assert(ps);
	return ps->top == -1;
}

void StackDestory(Stack* ps) {
	assert(ps);
	if (ps->a) {
		free(ps->a);
		ps->a = NULL;
		ps->top = 0;
		ps->capacity = 0;
	}
}

typedef struct {
    Stack sout;
    Stack sin;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* mq = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&mq->sout);
    StackInit(&mq->sin);
    return mq;
}

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->sin,x);
}

int myQueuePop(MyQueue* obj) {
    while(StackSize(&obj->sin)>1){
        StackPush(&obj->sout,StackTop(&obj->sin));
        StackPop(&obj->sin);
    }
    int top = StackTop(&obj->sin);
    StackPop(&obj->sin);
    while(StackSize(&obj->sout)){
        StackPush(&obj->sin,StackTop(&obj->sout));
        StackPop(&obj->sout);
    }
    return top;
}

int myQueuePeek(MyQueue* obj) {
    return (&obj->sin)->a[0];
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->sin);
}

void myQueueFree(MyQueue* obj) {
    StackDestory(&obj->sin);
    StackDestory(&obj->sout);
    free(obj);
    obj = NULL;
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

其实理解了思路的方法,去编写代码就非常简单的了,如果还是有瓶颈很难编写,那么可能是对栈的理解没有打好基础,要多去回顾一下之前的知识喔。 

二、用队列实现栈

1.题目理解

其实看了这题目会发现它跟上一个题目几乎一模一样的,但是要实现的话会有些稍稍的不一样,接下来我们讲讲思路吧。

2.思路

我们想要实现队列实现栈的话就不能用第一题的思路,因为这完全就是两道题,那么思路的话,我们只需要将出队的n-1个元素全面出到第二个队列里,留下队尾最后一个元素,那么我们单独弹出,就能实现堆的后进先出功能,如果不太明白可以看看下面图,会好理解些,只要我们每一次像栈一样出栈,用以上的思路就可以完成啦。

3.代码编写


typedef int DataType;

typedef struct QListNode {
	DataType val;
	struct QListNode* next;
}QNode;

typedef struct Queue {
	QNode* phead;
	QNode* plist;
	int size;
}Queue;

//初始化队列
void QListInit(Queue* q) {
	assert(q);
	q->phead = q->plist = NULL;
	q->size = 0;
}
//队列入队列
void QListPush(Queue* q, DataType x) {
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc newnode");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;
	if (q->phead == NULL) {
		q->phead = q->plist = newnode;
	}
	else {
		q->plist->next = newnode;
		q->plist = newnode;
	}
	q->size++;
}
//队列出队列
void QListPop(Queue* q) {
	assert(q);
	assert(q->phead);
	QNode* del = q->phead;
	if (del->next == NULL) {
		free(del);
		q->phead = q->plist = NULL;
	}
	else {
		QNode* next = del->next;
		free(del);
		del = NULL;
		q->phead = next;
	}
	q->size--;
}
//获取队列头部元素
DataType QueueFront(Queue* q) {
	assert(q);
	assert(q->phead);
	return q->phead->val;
}
//获取队列尾部元素
DataType QueueBack(Queue* q) {
	assert(q);
	assert(q->plist);
	return q->plist->val;
}
//获取队列的元素个数
int QueueSize(Queue* q) {
	assert(q);
	assert(q->phead);
	return q->size;
}
//检测队列为空 空=TRUE
bool QueueEmpty(Queue* q) {
	assert(q);
	return q->phead == NULL;
}
//销毁队列
void QListDestory(Queue* q) {
	assert(q);
	QNode* tail = q->phead;
	while (tail) {
		QNode* next = tail->next;
		free(tail);
		tail = next;
	}
	q->phead = q->plist = NULL;
	q->size = 0;
}

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* qst = (MyStack*)malloc(sizeof(MyStack));
    QListInit(&qst->q1);
    QListInit(&qst->q2);
    return qst;
}

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))
        QListPush(&obj->q1,x);
    else
        QListPush(&obj->q2,x);
}

int myStackPop(MyStack* obj) {
    Queue* empty = &obj->q1; 
    Queue* nonempty = &obj->q2;
    if(!(QueueEmpty(empty))){
        empty = &obj->q2; 
        nonempty = &obj->q1;
    }
    while(QueueSize(nonempty) > 1){
        QListPush(empty,QueueFront(nonempty));
        QListPop(nonempty);
    }
    int top = QueueFront(nonempty);
    QListPop(nonempty);
    return top;
}

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

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    QListDestory(&obj->q1);
    QListDestory(&obj->q2);
    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

总结

以上是栈和队列相互关系的讲解啦,有点可笑的是我们用栈实现队列,用队列实现栈,确实很抽象哈哈哈,但是这也是我们需要掌握的知识点,感谢大家观看喔。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值