栈与队列的互相模拟和循环队列

1.用两个队列模拟一个栈

分析:栈是后进先出的,队列是先进先出的。要想实现栈,就需要将最后进队列的元素先出,则只需要一个队列为空,一个队列用来接受元素。当要进栈的时候,要将元素插入到一个非空的队列中,保持另一个是空队列;当要出栈的时候,将非空队列的元素逐步出到另一个空队列中,当非空队列只有一个元素的时候,将此时的元素出队列,并且不在入另一个队列,此时的元素就是出栈的元素。
【相关函数的实现】

typedef int QDatatype;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;
typedef struct {
	Queue q1;
	Queue q2;
} MyStack;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDatatype x);
void QueuePop(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
QDatatype QueueFront(Queue* pq);
QDatatype QueueBack(Queue* pq);

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* p = pq->head;
	QNode* q = NULL;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	QNode* s = (QNode*)malloc(sizeof(QNode));
	if (s == NULL)
	{
		perror("malloc fail");
		return;
	}
	s->data = x;
	s->next = NULL;
	if (pq->head == NULL)
	{
		pq->head = pq->tail = s;
	}
	else
	{
		pq->tail->next = s;
		pq->tail = s;
	}
	pq->size++;
}
void QueuePop(Queue* pq)
{
	assert(pq);
	QNode* p = pq->head;
	if (pq->head == pq->tail)
	{
		pq->head  = pq->head->next;
		pq->tail = pq->head;
	}
	else
	{
		pq->head = pq->head->next;
	}
	free(p);
	pq->size--;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return !(pq->size);
}
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;
}

MyStack* myStackCreate() {
	MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
	if (obj == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	QueueInit(&obj->q1);
	QueueInit(&obj->q2);
	return obj;
}

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

int myStackPop(MyStack* obj) {
	assert(obj);
	Queue* empty = &obj->q1;
	Queue* nonempty = &obj->q2;
	if (!(QueueEmpty(&obj->q1)))
	{
		empty = &obj->q2;
		nonempty = &obj->q1;
	}
	while (nonempty->size > 1)
	{
		int tmp = QueueFront(nonempty);
		QueuePush(empty, tmp);
		QueuePop(nonempty);
	}
	int top = QueueFront(nonempty);
	QueuePop(nonempty);
	return top;
}

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

bool myStackEmpty(MyStack* obj) {
	assert(obj);
	if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2))
	{
		return 1;
	}
	else
		return 0;
}

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

2.用两个栈来实现队列的操作

分析:栈是后进先出的,队列是先进先出的。进栈会将原来的顺序逆置,则只需要进两次栈就可以保持原来的顺序不变。进队列的时候,将元素进入进栈的栈中;出队列的时候,将出出栈中元素,当出栈的位空的时候,在将进栈的元素全部进到出栈中,此时在出出栈中的元素。
【函数实现】

typedef int SElemType;

typedef struct snode
{
	SElemType data;
	struct snode* next;
}SNode,*LinkStack;


typedef struct 
{
    LinkStack push_stack;
    LinkStack pop_stack;
} MyQueue;
void destroy_LinkStack(LinkStack* LS);
void init_LinkStack(LinkStack* LS);
int empty_LinkStack(LinkStack S);
int get_top_LinkStack(LinkStack S, SElemType* e);
int LengthLinkStack(LinkStack S);
int push_LinkStack(LinkStack* LS, SElemType x);
int pop_LinkStack(LinkStack* LS, SElemType* e);
//链栈的初始化
void init_LinkStack(LinkStack* LS)
{
	assert(LS);
	*LS = NULL;
}

//判断是否栈空
int empty_LinkStack(LinkStack S)
{
	//assert(S);
	if (S == NULL)return 1;
	else return 0;
}

//获取栈顶元素
int get_top_LinkStack(LinkStack S, SElemType* e)
{
	assert(S);
	*e = S->data;
	return 1;
}

//求栈的长度
int LengthLinkStack(LinkStack S)
{
	int n = 0;
	LinkStack p = S;
	while (p)
	{
		n++;
		p = p->next;
	}
	return n;
}

//链栈的进栈操作
int push_LinkStack(LinkStack* LS, SElemType x)
{
	LinkStack s = (LinkStack)malloc(sizeof(SNode));
	if (s == NULL)
	{
		perror("malloc fail");
		return 0;
	}
	s->data = x;
	s->next = NULL;
	if (*LS == NULL)
	{
		*LS = s;
	}
	else
	{
		s->next = (*LS)->next;
		(*LS)->next = s;
	}
	return 1;
}

//链栈的出栈操作
int pop_LinkStack(LinkStack* LS, SElemType* e)
{
	assert(!empty_LinkStack(*LS));
	LinkStack p = *LS;
	*LS = (*LS)->next;
	*e = p->data;
	free(p);
	return 1;
}

//链栈的销毁操作
void destroy_LinkStack(LinkStack* LS)
{
	LinkStack p = *LS;
	LinkStack q = NULL;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	*LS = NULL;
}

MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    init_LinkStack(&obj->push_stack);
    init_LinkStack(&obj->pop_stack);
    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    push_LinkStack(&obj->push_stack,x);
}

int myQueuePop(MyQueue* obj) {
    assert(obj);
    if(empty_LinkStack(obj->pop_stack))
    {
        while(!empty_LinkStack(obj->push_stack))
        {
            SElemType e=0;
            get_top_LinkStack(obj->push_stack,&e);
            push_LinkStack(&obj->pop_stack,e);
            pop_LinkStack(&obj->push_stack,&e);
        }
    }
    SElemType top=0;
    pop_LinkStack(&obj->pop_stack,&top);
    return top;
}

int myQueuePeek(MyQueue* obj) {
    assert(obj);
    if(empty_LinkStack(obj->pop_stack))
    {
        while(!empty_LinkStack(obj->push_stack))
        {
            SElemType e=0;
            get_top_LinkStack(obj->push_stack,&e);
            push_LinkStack(&obj->pop_stack,e);
            pop_LinkStack(&obj->push_stack,&e);
        }
    }
    SElemType top=0;
    get_top_LinkStack(obj->pop_stack,&top);
    return top;
}

bool myQueueEmpty(MyQueue* obj) {
    assert(obj);
    return empty_LinkStack(obj->push_stack)&&empty_LinkStack(obj->pop_stack) ;
}

void myQueueFree(MyQueue* obj) {
    assert(obj);
    destroy_LinkStack(&obj->pop_stack);
    destroy_LinkStack(&obj->push_stack);
    free(obj);
}

3.循环队列

分析:循环队里的特点是提前知道需要多大的空间,并提前开辟好空间。此时关键是要判断什么时候是空队列,什么时候是满队列,为了方便判断,在开辟空间的时候需要多开辟一块空间。因为是提前知道需要多少空间,开辟数组会比链式结构简单。此时设置队头和队尾的参数,队头指向的队头的元素,队尾指向的队尾元素的下一个位置。再设置一个循环队列的长度,用于方便取模来表示循环。注意:在队头队尾相加减的时候要注意取模。
【函数实现】

typedef struct {
    int*a;
    int front;
    int rear;
    int size_queue;
} MyCircularQueue;

bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    obj->a=(int *)malloc((k+1)*sizeof(int));
    if(obj->a==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    obj->front=obj->rear=0;
    obj->size_queue=k+1;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    obj->a[obj->rear]=value;
    obj->rear=(obj->rear+1)%obj->size_queue;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front=(obj->front+1+obj->size_queue)%obj->size_queue;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
    {
        int rear=(obj->rear-1+obj->size_queue)%obj->size_queue;
        return obj->a[rear];
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if((obj->rear+1)%obj->size_queue==obj->front)
        return true;
    else
        return false;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

杰深入学习计算机

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

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

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

打赏作者

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

抵扣说明:

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

余额充值