因为本期使用C语言来实现代码,由于C语言不支持队列,所以我们要先实现队列的模拟。
队列的结构特点和实现
队列的结构特点:只允许在一端进行插入数据操作,在另一端进行删除数据的操作,队列具有先进先出的特点。如图:
队列的实现:可以用数组或者链表来实现队列,如果用数组来实现队列,出队列涉及数组元素的移动,效率比较低下;如果用链表实现队列,将单链表头设为队头,链表的尾就是队尾,入队就是尾插,出队就是头删,另外在单链表的结构基础上增加一个尾指针指向链表的尾节点,方便尾插效率会快很多。
用链表实现队列:
typedef int QDataType;
//链式结构
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
//队列的结构
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
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->tail = pq->head = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* newhead = pq->head->next;
free(pq->head);
pq->head = newhead;
}
pq->size--;
}
int QueueSize(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;
}
题目:用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
注意:
- 你只能使用队列的标准操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。 - 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
typedef struct {
} MyStack;
MyStack* myStackCreate() {
}
void myStackPush(MyStack* obj, int x) {
}
int myStackPop(MyStack* obj) {
}
int myStackTop(MyStack* obj) {
}
bool myStackEmpty(MyStack* obj) {
}
void myStackFree(MyStack* obj) {
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
思路
用队列实现入栈操作很容易,由于栈只允许在固定的一端进行插入和删除元素操作,而队列只允许在一端进行插入数据操作,在另一端进行删除数据的操作,所以我们要出栈的时候要拿到队列队尾的元素4,而把队尾前面的元素1、2、3移动到另一个空队列中。
于是,整体思路大体为:
两个队列初始状态都为空,入栈的时候将n个数据从队尾入队到第一个队列中,如果需要出栈,也就是删除队尾元素,就将第一个队列中前n-1个数据都移动到第二个队列中,此时第一个队列中剩下的元素就是我们要删除的栈顶元素,删除元素之后,第一个队列就为空,此时如果想要入栈插入元素,就把元素入队到第二个队列,如果想要出栈,再利用第一个队列移动元素。
也就是说,两个队列保持一个为空,向不为空的队列插入元素,如果想要删除元素,就用空的队列来倒元素。
如果想要获取栈顶元素,我们只要获取队尾元素即可;如果想要判断栈是否为空,就判断两个栈是否都为空。
代码(C语言版)
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
void QueueInit(Queue* pq)
{
assert(pq);
pq->tail = pq->head = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* newhead = pq->head->next;
free(pq->head);
pq->head = newhead;
}
pq->size--;
}
int QueueSize(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;
}
typedef struct {
Queue queue1;
Queue queue2;
} MyStack;
MyStack* myStackCreate() {
MyStack* pst=(MyStack*)malloc(sizeof(MyStack));
if(pst==NULL)
{
perror("malloc");
return NULL;
}
QueueInit(&pst->queue1);
QueueInit(&pst->queue2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->queue1))
{
QueuePush(&obj->queue1,x);
}
else
{
QueuePush(&obj->queue2,x);
}
}
int myStackPop(MyStack* obj)
{
Queue* empty=&obj->queue1;
Queue* noempty=&obj->queue2;
if(!QueueEmpty(&obj->queue1))
{
empty=&obj->queue2;
noempty=&obj->queue1;
}
while(QueueSize(noempty)>1)
{
QueuePush(empty,QueueFront(noempty));
QueuePop(noempty);
}
int top=QueueFront(noempty);
QueuePop(noempty);
return top;
}
int myStackTop(MyStack* obj)
{
if(!QueueEmpty(&obj->queue1))
{
return QueueBack(&obj->queue1);
}
else
{
return QueueBack(&obj->queue2);
}
}
bool myStackEmpty(MyStack* obj) {
bool ret=QueueEmpty(&obj->queue1)&&QueueEmpty(&obj->queue2);
return ret;
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->queue1);
QueueDestroy(&obj->queue2);
free(obj);
}
持续更新,下期见
(下期内容:用栈实现队列)