대기열을 사용하여 스택 구현(다이어그램은 매우 상세함)

소개

스택과 대기열에 대한 지식을 이해한 후 우리는 이미 그 특성에 대해 어느 정도 이해했습니다. 스택은 선입선출 방식이고 대기열은 선입선출 방식
입니다
.

다음 두 기사에서는 두 개의 대기열이 있는 스택을 구현하고 두 개의 스택이 있는 대기열을 구현하는 OJ 사례를 소개합니다.
대기열을 사용하여 스택 OJ 링크 구현

큐로 스택 구현

주제 소개

여기에 이미지 설명 삽입
제목 설명은 매우 간단합니다.
두 개의 대기열, 즉 선입선출을 통해 스택 스토리지 데이터의 특성을 실현합니다.

push, pop, top, empty, free를 구현해야 합니다: void push(int x)는 요소 x 를 스택의 맨 위로 푸시
합니다 . 스택의 최상위 요소, bool empty() 스택이 비어 있으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.


아이디어에 대한 간략한 설명

이 질문의 어려움은 큐의 특성이 선입 선출이므로 큐 끝에 있는 요소를 직접 제거할 수 없기 때문에 큐에 나중에 저장된 요소를 팝하는 방법입니다. 두 번째 대기열을 사용하여 대기열의 요소를 다른 대기열로 전송하고 원래 대기열에 하나의 요소만 남기고 나머지 요소는 마지막으로
입력된 요소이므로 이 요소를 제거하는 것을 쉽게 생각할 수 있습니다.
마지막에 요소를 제거하고 싶다면 Queue에 있는 요소를 다시 원래 Queue로 옮기고 남은 요소를 삭제하고
이때 요소를 삽입하려면 요소와 함께 Queue 끝에 직접 삽입 그게 다야, 제거 할 때 다시 부어주세요.

한 큐에서 순서대로 큐의 헤드에서 요소를 제거한 다음 다른 큐에 순서대로 삽입하면 데이터의 순서가 변경되지 않기 때문입니다. 따라서 끝에 요소를 삽입하려면 요소가 있는 큐에 직접 삽입할 수 있으며, 마지막에 삭제할 때는 데이터를 반복해서 반전하면 됩니다.

여기에 이미지 설명 삽입

성취하다

대기열의 일부

두 개의 큐로 스택을 구현하기 전에 스택을 구현할 때 바로 재사용할 수 있는 큐의 인터페이스를 구현해야 합니다. 큐의 구현은 여기에서 반복되지 않으며 이전 기사에서 자세히 소개되었습니다. 여기에서 대기열을 정의하는 데 사용되는 구조를 포함하여 이전에 구현된 대기열의 다양한 인터페이스를 직접 복사합니다.

typedef int QDataType;

typedef struct QListNode//队列的每个结点
{
    
    
	struct QListNode* pNext;
	QDataType data;
}QNode;

typedef struct Queue// 队列的结构
{
    
    
	QNode* front;
	QNode* rear;
	int size;
}Queue;

// 队列的部分
// 初始化队列
void QueueInit(Queue* pq)
{
    
    
	assert(pq);
	pq->front = NULL;
	pq->rear = NULL;
	pq->size = 0;
}
// 检测队列是否为空,如果为空返回非0,非空返回0
int QueueEmpty(Queue* pq)
{
    
    
	assert(pq);
	return pq->front == NULL;
}
// 队尾入队列
void QueuePush(Queue* pq, QDataType data)
{
    
    
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);
	newnode->data = data;
	newnode->pNext = NULL;
	if (QueueEmpty(pq))
	{
    
    
		pq->front = newnode;
		pq->rear = newnode;
	}
	else
	{
    
    
		pq->rear->pNext = newnode;
		pq->rear = newnode;
	}
	pq->size++;
}
// 队头出队列
void QueuePop(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	QNode* cur = pq->front->pNext;
	if (cur)
	{
    
    
		free(pq->front);
		pq->front = cur;
	}
	else
	{
    
    
		free(pq->front);
		pq->front = NULL;
		pq->rear = NULL;
	}
	pq->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	return pq->front->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{
    
    
	assert(pq && QueueEmpty(pq)==0);
	return pq->rear->data;
}
// 销毁队列
void QueueDestroy(Queue* pq)
{
    
    
	assert(pq);
	QNode* cur = pq->front;
	QNode* next = pq->front;
	while (cur)
	{
    
    
		next = cur->pNext;
		free(cur);
		cur = next;
	}
	pq->front = NULL;
	pq->rear = NULL;
	pq->size = 0;
}

스택의 일부

대기열을 구현하면 두 개의 대기열 q1과 q2를 만들고 이 두 대기열을 쉽게 액세스할 수 있도록 구조 변수에 저장해야 합니다.

typedef struct //两个队列
{
    
    
	Queue q1;
	Queue q2;
} MyStack;

스택 생성

이 인터페이스의 경우 제목에 매개변수가 제공되지 않습니다. MyStack 구조를 위한 공간을 동적으로 열고 초기화합니다.
초기화할 때 큐 초기화 함수인 QueueInit를 직접 재사용하여 두 개의 큐를 초기화할 수 있습니다.

//创建栈
MyStack* myStackCreate() 
{
    
    
	MyStack* pmst = (MyStack*)malloc(sizeof(MyStack));
	assert(pmst);
	QueueInit(&pmst->q1);
	QueueInit(&pmst->q2);
	return pmst;
}

스택이 비어 있는지 확인

스택이 비어 있습니다. 즉, 두 대기열이 모두 비어 있습니다.
따라서 QueueEmpty 함수를 직접 재사용하여 큐가 비어 있는지 여부를 판단하는데, 두 큐가 모두 비어 있을 때 즉, 두 함수의 반환 값이 모두 true이면 true를 반환하고 그렇지 않으면 false를 반환합니다.

//判断栈是否为空为空返回1,非空返回0
bool myStackEmpty(MyStack* obj)
{
    
    
	assert(obj);
	if (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2))//当两个队列全为空时才为空
	{
    
    
		return 1;
	}
	else
	{
    
    
		return 0;
	}
}

스택 푸시

스택을 푸시할 때 비어 있지 않은 요소를 큐에 삽입해야 하며, 모두 비어 있으면 임의로 하나만 삽입하면 됩니다
여기에 이미지 설명 삽입
.

//从栈顶入栈
void myStackPush(MyStack* obj, int x) 
{
    
    
	assert(obj);
	if (QueueEmpty(&obj->q1)==0)//在有数据的那个队列入栈
	{
    
    
        assert(QueueEmpty(&obj->q2));
		QueuePush(&obj->q1, x);
	}
	else
	{
    
    
        assert(QueueEmpty(&obj->q1));
		QueuePush(&obj->q2, x);
	}
}

튀어나와

스택을 팝할 때 요소가 하나 남을 때까지 요소가 있는 큐의 요소를 빈 큐로 전송해야 합니다. 이 요소만 제거하면 됩니다.
여기에 이미지 설명 삽입
요소를 전송할 때 QueueFront 함수를 재사용하여 큐의 헤드에서 요소를 제거한 다음 QueuePush를 사용하여 다른 큐의 끝에 삽입할 수 있습니다. 그런 다음 QueuePop에서 원래 대기열의 첫 번째 요소를 삭제합니다.

//从栈顶出栈
int myStackPop(MyStack* obj) 
{
    
    
	assert(obj && myStackEmpty(obj)==0);
	QDataType ret = 0;
	//将有数据的那个队列转移到空队列中,返回剩下的那个数据
	if(QueueEmpty(&obj->q1)==0 && QueueEmpty(&obj->q2))
	{
    
    
		while (obj->q1.size > 1)
		{
    
    
			QueuePush(&obj->q2, QueueFront(&obj->q1));
			QueuePop(&obj->q1);
		}
		ret = QueueFront(&obj->q1);
		QueuePop(&obj->q1);
	}
	else if (QueueEmpty(&obj->q2)==0 && QueueEmpty(&obj->q1))
	{
    
    
		while (obj->q2.size > 1)
		{
    
    
			QueuePush(&obj->q1, QueueFront(&obj->q2));
			QueuePop(&obj->q2);
		}
		ret = QueueFront(&obj->q2);
		QueuePop(&obj->q2);
	}
	else
	{
    
    
		return EOF;
	}
	return ret;
}

스택의 최상위 요소에 액세스

스택의 최상위 요소에 액세스할 때 요소가 있는 큐의 꼬리 요소에 액세스하면 충분합니다.
대기열의 꼬리 요소에 액세스하는 QueueBack 함수를 직접 재사용할 수 있습니다.

//访问栈顶元素
int myStackTop(MyStack* obj) 
{
    
    
	assert(obj && myStackEmpty(obj) == 0);
	QDataType ret = 0;
	if (QueueEmpty(&obj->q1) == 0 && QueueEmpty(&obj->q2))//访问有数据的那个队列的尾数据
	{
    
    
		ret = QueueBack(&obj->q1);
	}
	else if (QueueEmpty(&obj->q2) == 0 && QueueEmpty(&obj->q1))
	{
    
    
		ret = QueueBack(&obj->q2);
	}
	else
	{
    
    
		return EOF;
	}
	return ret;
}

스택 릴리스

스택을 해제할 때 대기열 해제 함수인 QueueDestroy를 직접 재사용하여 각각 두 개의 대기열을 해제합니다. 마지막으로 동적으로 생성된 구조체 변수를 해제합니다.

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

요약하다

지금까지 스택을 구현하기 위해 두 개의 큐를 사용하는 주제는 끝났습니다.다음 기사에서는 큐를 구현하기 위해 두 개의 스택을 사용하는 방법을 소개할 것입니다. 여러분의 지속적인 관심을 환영합니다.

제가 특정 부분을 명확하게 소개하지 않았거나 특정 부분에 문제가 있다고 생각하시면 댓글란에 올려주세요.

이 글이 도움이 되셨다면 클릭 한번으로 연결되길 바랍니다

당신과 함께 발전하기를 바랍니다

Supongo que te gusta

Origin blog.csdn.net/weixin_73450183/article/details/129740552
Recomendado
Clasificación