栈和队列的有关面试题

用队列实现栈

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

                

分析:  第一步:首先我们要自己写一个队列,参考上篇博客。 

//队列节点类型声明:
typedef int quenedate;
typedef struct qnode
{
	quenedate date;
	struct qnode* next;
}qnode;

//队列类型声明:
typedef struct quene
{
	struct qnode* head;
	struct qnode* tail;
	int size;
	
}quene;


//队列的初始化:
void queuelint(quene* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}




// 队尾入队列 
void QueuePush(quene* q, quenedate data)
{
	assert(q);

	//创建结点;
	qnode* newnode = (qnode*)malloc(sizeof(qnode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}

	newnode->date = data;
	newnode->next = NULL;

	//将结点连接到队列上
	if (q->tail == NULL)
	{
		q->head = q->tail = newnode;
		q->size++;

	}
	else
	{
		q->tail->next = newnode;
		q->size++;
		q->tail = q->tail->next;
	}
}


//判断是否为空队列
bool QueueEmpty(quene* q)
{
	assert(q);
	
	return q->size == 0;
}




// 队头出队列 
void QueuePop(quene* q)
{
	assert(q);

	//断言队列不能为空;
	assert(!QueueEmpty(q));

	//队列里只有一个结点;
	if (q->head ->next==NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
		q->size--;
	}
	//队列里不止有一个结点;
	else
	{
		qnode* tmp = q->head;
		q->head = q->head->next;
		free(tmp);
		tmp = NULL;
		q->size--;
	}

}


// 获取队列头部元素 
quenedate QueueFront(quene* q)
{
	assert(q);

	//断言队列不能为空;
	assert(!QueueEmpty(q));

	return q->head->date;
}



// 获取队列队尾元素 
quenedate QueueBack(quene* q)
{
	assert(q);

	//断言队列不能为空;
	assert(!QueueEmpty(q));

	return q->tail->date;
}


// 获取队列中元素个数 
int QueueSize(quene* q)
{
	assert(q);
	return q->size;
}




// 销毁队列 
void QueueDestroy(quene* q)
{
	assert(q);

	if (QueueEmpty(q))//队列里没有结点
	{
		q->head = q->tail = NULL;
		q->size = 0;
		return;
	}

	//队列里有结点;
	qnode* cur = q->head;
	while (cur)
	{
		qnode* tmp = cur->next;
		free(cur);
		cur = tmp;
	}
	q->head = q->tail = NULL;
	q->size = 0;	
}

                这样我们就有了队列,然后来定义自己的栈类型,由两个队列q1, q2组成; 

typedef struct MyStack
{
    quene q1;
    quene q2;

} MyStack;

                然后,我们来创建我们的栈,为它开辟空间,然后初始化里面的两个队列; 

MyStack* myStackCreate() 
{

	
    MyStack* tsp=(MyStack*)malloc(sizeof(MyStack));
    queuelint(&tsp->q1);
    queuelint(&tsp->q2);
    return tsp;


}

       将元素 x 压入栈顶。实现方法是:如果栈中的队列q1为空,则将数据放入q1中;否则放q2; 

 就是将两个队列,一个队列空下来,将数据都放到另外一个队列里;

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

判断栈是否为空,只需要判断栈里的两个队列是否为空即可;

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

销毁栈,只需要先销毁栈中的两个队列,再销毁栈即可; 

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

        返回栈顶元素。这里的方法是:数据都放到一个队列中了,另外一个队列没有数据。直接返回非空队列的队尾数据即可;

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

                移除并返回栈顶元素:数据都存放再一个队列中,另外一个队列里没有数据,将非空队列里的size-1个元素放到空队列里,并移除;然后非空队列里的剩下那个数据就是栈顶元素,返回并移除它; 

int myStackPop(MyStack* obj)
{
		//将栈中的两个队列q1,q2分为一个空队列和一个非空队列;
	  quene* empty=&obj->q1;
    quene* unempty=&obj->q2;

		//判断q1是否为空;若q1为空则q1就是空队列,否则q2为空队列;
    if(QueueEmpty(&obj->q1))
    {
        empty=&obj->q1;
        unempty=&obj->q2;
    }
		else
		{
				empty=&obj->q2;
    		unempty=&obj->q1;
		}


    //前非空队列里的size-1个元素导入到空队列;
    while(QueueSize(unempty) > 1)
    {
        QueuePush(empty,QueueFront(unempty));
        QueuePop(unempty);

    }

    int top=QueueFront(unempty);
     QueuePop(unempty);

    return top;

}

用栈实现队列

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

 分析:  第一步:首先我们要自己写一个队列,参考上篇博客。 

typedef int stackdate;
typedef struct stack
{
	stackdate* date;
	int top;
	int capatity;
}st;



///栈的初始化:
void stinit(st* ps)
{
	assert(ps);
	ps->date = NULL;
	ps->top = 0;
	ps->capatity = 0;
}


//栈的销毁
void stdestory(st* ps)
{
	assert(ps);
	free(ps->date);
	ps->date = NULL;

	ps->top = 0;
	ps->capatity = 0;

}


//压栈:
void stpush(st* ps, stackdate x)
{
	assert(ps);

	//判断栈数据容量是否满了
	if (ps->top == ps->capatity)
	{
		int newcapatity = ps->capatity == 0 ? 4 : ps->capatity * 2;

		stackdate* tmp = (stackdate*)realloc(ps->date, sizeof(stackdate) * (ps->capatity));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);
		}

		ps->date = tmp;
		ps->capatity = newcapatity;
	}

	//存入数据;
	ps->date[ps->top] = x;
	ps->top++;

}



//出栈:
void stpop(st* ps)
{
	assert(ps);

	assert(ps->top > 0);

	ps->top--;
}



//栈内的元素个数:
int stsize(st* ps)
{
	assert(ps);

	return ps->top;
}



//清空栈:
void stempty(st* ps)
{
	assert(ps);

	ps->top = 0;
}

//拿出栈顶元素;
stackdate sttop(st* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->date[ps->top-1];
}


//判断是否为空栈:
bool emptyst(st* ps)
{
	assert(ps);

	return ps->top == 0;
}

这样我们就有了栈,然后来定义自己的队列类型,由两个栈pushst, popst组成;  

typedef struct  MyQueue
{
    st pushst;
    st popst;
} MyQueue;

然后,我们来创建我们的队列,为它开辟空间,然后初始化里面的两个栈; 

MyQueue* myQueueCreate() 
{

    MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));
    stinit(&obj->pushst);
    stinit(&obj->popst);

    return obj;

}

将元素 x 推到队列的末尾,方法是:将x入栈到pushst即可; 

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

返回队列开头的元素,第一步:倒pushst中的数据到popst中,第二步:返回popst中的栈顶元素;

int myQueuePeek(MyQueue* obj)
 {
     //倒pushst中的数据到popst中:
     while( stsize(&obj->pushst)>0)
     {
         stpush(&obj->popst, sttop(&obj->pushst));
         stpop(&obj->pushst);
     }

		//返回popst中的栈顶元素;
     return sttop(&obj->popst);
}

从队列的开头移除并返回元素, 第一步:倒pushst中的数据到popst中,第二步:返回popst中的栈顶元素,第三步,移除popst栈顶的元素;

int myQueuePop(MyQueue* obj)
 {
     int front=myQueuePeek(obj);

     stpop(&obj->popst);

     return front;
}

如果队列为空,返回 true ;否则,返回 false;方法是,只要pushst与popst两个栈的数据都为空,则队列数据为空; 

bool myQueueEmpty(MyQueue* obj) 
{
    if(emptyst(&obj->pushst) && emptyst(&obj->popst))
    {
        return true;
    }
    else
    {
        return false;
    }
}

最后将队列销毁即可;

void myQueueFree(MyQueue* obj) 
{
    stdestory(&obj->pushst);
    stdestory(&obj->popst);

    free(obj);
}

设计循环队列

                        链接:622. 设计循环队列 - 力扣(LeetCode)

类型定义

                a是用来存放数据的数组空间,k是循环队列的容量,head和real用来访问数组,并且判断队列是否已经满了;

typedef struct MyCircularQueue
{
    int *a;
    int head;
    int real;
    int k;
} MyCircularQueue;

 

设置队列长度为 k 

                为队列和队列中的数组开辟空间;a为存放数据的数组;k为队列容量,定义real=0用来访问数组的下标,每次添加元素后real++,也可以理解为有效元素个数;head=0用来判断队列是否已经满了;需要注意的是我们开辟的数组空间有k+1个元素,最后一个位置不存放数据;

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    obj->a=(int *)malloc((k+1)*sizeof(int));

    obj->k=k;

    obj->head=obj->real=0;

    return obj;
    
}

检查循环队列是否为空         

        由上图看出head==real是队列为空;

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->head==obj->real;
}

检查循环队列是否已满 

        由图上可以看出在逻辑上只要real+1==head队列就算满,但是现在head一直为0;real是下

标,现在为k;那么靠什么可以实现上面的逻辑呢?我们的方法是只需要(real+1)%(k+1)==head(可以带值理解),队列就算满;依靠上面的式子可以实现循环逻辑;

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->real+1)%(obj->k+1)==obj->head;;
}

向循环队列插入一个元素。如果成功插入则返回真

        首先我们来判断队列是否已满,如果满了则直接返回false;未满则利用real来访问数组存放数据;然后real++,在使real %= (k+1)目的是满足循环的条件;

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
 {
     if(myCircularQueueIsFull(obj))
     {
         return false;
     }

     obj->a[obj->k]=value;
     obj->real++;
     obj->real %=(obj->k+1);
     
     return true;

}

 从循环队列中删除一个元素。如果成功删除则返回真。 

        首先判断是否为空队列,如果是空队列则直接返回false;如果非空,则使得head++;

在使得head %= (k+1);目的是满足循环的条件;

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if( myCircularQueueIsEmpty( obj))
    {
        return false;
    }

    obj->head++;

    obj->head %=(obj->k+1);

    return true;
}

从队首获取元素。如果队列为空,返回 -1 。 

                非空直接返回下标为head的元素即可;

nt myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }

    return obj->a[obj->head];
}

获取队尾元素。如果队列为空,返回 -1 。 

                因为real目前是元素的个数,它的下标的前一个数据才是队尾元素,并且我们还要满足队列的循环结构,因此返回下标为(real+k)%(k+1)的元素(可以带值理解);

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->real+obj->k)%(obj->k+1)];
}

队列的销毁

        直接释放空间即可; 

void myCircularQueueFree(MyCircularQueue* obj)
 {

     free(obj->a);
     free(obj);
}

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

(int*) nightfall

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值