栈和队列的相互实现

目录

栈和队列的比较

栈实现队列

代码实现

队列实现栈

代码实现


栈和队列的比较

队列和栈是两种不同的数据结构。它们有以下区别:

(1)操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。

(2)可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。

(3)操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(不允许中途离队)。而栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除。

但是他们两也有一个共同点就是只允许在端点处插入和删除元素。

所以两者可以相互实现,也就是栈实现队列,队列实现栈。

栈实现队列

 leetcode链接:栈实现队列

栈实现队列的思想就是通过两个栈,一个入值栈,一个出值栈,这样就可以实现队尾入队头出,先进先出的原则。

 然后将pushST的值全部送到popST中

 最后就是popST的出栈

这样就可以通过两个栈来实现队列了。 

代码实现

解析内容已经在代码的注释中给出。

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int capacity;
	int top;
}ST;

bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}


void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			printf("realloc failed\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}

int StackSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

//以上内容是栈的基本实现,之前文章中已经提到。

typedef struct {
    ST pushST;
    ST popST;
} MyQueue;  //这里定义两个栈,包含在结构体Queue中


//我的队列的创建,也就是pushST和popST的创建
MyQueue* myQueueCreate() {
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));//malloc出空间
    StackInit(&q->pushST);//初始化pushST栈
    StackInit(&q->popST); //初始化popST栈
    return q;
}

//入队列也就是入值到pushST中,通过入栈操作实现
void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushST,x); 
}

//从队列的开头移除并返回元素
int myQueuePop(MyQueue* obj) {
    if(StackEmpty(&obj->popST)) //先判断是否为空
    {
        //如果popST为空的话,需要先将pushST的值全部入到popST。
        while(!StackEmpty(&obj->pushST))
        {
            //pushST到popST也是后者进入一个元素,前者删除一个元素,循环操作直到pushST空
            StackPush(&obj->popST,StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    //将popST的值赋给front,然后再将其通过出栈操作出栈,最后再返回front的值
    int front =  StackTop(&obj->popST);
    StackPop(&obj->popST);
    return front;//front的值就是队头的元素
}

// 返回队列开头的元素
int myQueuePeek(MyQueue* obj) {
        //先判断popsT是否尾空
        if(StackEmpty(&obj->popST))
        {
            while(!StackEmpty(&obj->pushST))
            {
                //和前面的操作一样,将pushST的值都给到popST中
                StackPush(&obj->popST,StackTop(&obj->pushST));
                StackPop(&obj->pushST);
            }
        }
    //直接找到队头元素也是popST的栈顶元素,直接返回这个值即可
    return StackTop(&obj->popST);
}

//如果队列为空,返回 true ;否则,返回 false
bool myQueueEmpty(MyQueue* obj) {
    //返回popST和pushST都为空的命题的真假,如果真就是返回true,假就返回false
    return StackEmpty(&obj->popST)&&StackEmpty(&obj->pushST);
}

//我的队列的销毁,也就是两个栈的销毁
void myQueueFree(MyQueue* obj) {
    //需要先销毁两个栈再去释放obj指针指向的空间
    StackDestroy(&obj->popST);
    StackDestroy(&obj->pushST);
    free(obj);
}

 


队列实现栈

  队列实现栈思想是通过两个队列来实现。入值时,往不为空的队列入,保持着另一个队列为空,出值时,总共n个数据,先将前面的n-1个数据转移到另一个队列,原来的队列就只剩下一个数据了,再将这个数据出队列就实现了先进后出,后进先出的操作。入值时需要入到有值的队列中去。

leetcode链接:225. 用队列实现栈 - 力扣(LeetCode)

将前面的n-1个元素转移到另一个队列 

 最后再将之前队列中唯一的元素出队列。

 这样就实现了栈的基本性质。

代码实现

 解析内容已经在代码的注释中给出。

typedef int QDataType;
 
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head==NULL;
}

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;	
	}
	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		pq->tail = pq->head = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QueueNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
	{
		pq->tail == NULL;
	}
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

int QueueSize(Queue* pq)
{
	assert(pq);
	int count = 0;
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		count++;
		cur = cur->next;
	}
	return count;
}
//以上内容是对于的队列的实现,前面的文章也有提到


//定义结构体中有两个队列
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


我的栈的创建,相当于两个队列的创建
MyStack* myStackCreate() {
    MyStack* st = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&st->q1);//初始化队列1
    QueueInit(&st->q2);//初始化队列2
    return st;
}

// 将元素 x 压入栈顶
void myStackPush(MyStack* obj, int x) {
    assert(obj);
//如果队列1不为空就入队列1,否则入队列2,当两个都为空时就是入队列2
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

//移除并返回栈顶元素
int myStackPop(MyStack* obj) {
    assert(obj);
    //先假设队列1是空,创建结构体指针emptyQ指向q1,nonempty2指向q2
    Queue* emptyQ = &obj->q1;
    Queue* nonemptyQ = &obj->q2;
//当前面的假设错误时,将两个指针所指向的内容互换
    if(!QueueEmpty(&obj->q1))
    {
        emptyQ = &obj->q2;
        nonemptyQ = &obj->q1;
    }
//循环将不为空的队列的元素转移到另一个队列,直到剩下一个元素
    while(QueueSize(nonemptyQ)>1)
    {
        //先是空队列的入队列,再是非空队列的出队列,通过前面的队列操作实现
        QueuePush(emptyQ,QueueFront(nonemptyQ));
        QueuePop(nonemptyQ);
    }
    //将队首元素给到front,也就是代表着栈的栈顶元素
    int top = QueueFront(nonemptyQ);
    QueuePop(nonemptyQ); //通过队列操作将这个元素去除
    return top;//返回top也就是栈顶元素
}

//返回栈顶元素
int myStackTop(MyStack* obj) {
    assert(obj);
    //判断队列1是否为空,非空就返回它的队尾元素
    //因为两个队列必须会有一个是空的,所以可以直接用if来判断倒是选择哪一个队列的队尾元素
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

//如果栈是空的,返回 true ;否则,返回 false 
bool myStackEmpty(MyStack* obj) {
    assert(obj);
    //返回队列1和队列2都是空的命题的真假,如果是真就返回true,否则就是false
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

//创建的栈的销毁
void myStackFree(MyStack* obj) {
    assert(obj);
    //销毁栈也就是销毁两个队列
    QueueDestroy(&obj->q1);//释放队列1空间
    QueueDestroy(&obj->q2);//释放队列2空间
    free(obj);//释放obj指针所指向的空间
    obj = NULL;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值