전체 텍스트 카탈로그
소개
스택과 대기열에 대한 지식을 이해한 후 우리는 이미 그 특성에 대해 어느 정도 이해했습니다. 스택은 선입선출 방식이고 대기열은 선입선출 방식
입니다
.
다음 두 기사에서는 두 개의 대기열이 있는 스택을 구현하고 두 개의 스택이 있는 대기열을 구현하는 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);
}
요약하다
지금까지 스택을 구현하기 위해 두 개의 큐를 사용하는 주제는 끝났습니다.다음 기사에서는 큐를 구현하기 위해 두 개의 스택을 사용하는 방법을 소개할 것입니다. 여러분의 지속적인 관심을 환영합니다.
제가 특정 부분을 명확하게 소개하지 않았거나 특정 부분에 문제가 있다고 생각하시면 댓글란에 올려주세요.
이 글이 도움이 되셨다면 클릭 한번으로 연결되길 바랍니다
당신과 함께 발전하기를 바랍니다