队列:
队列是一种常见的数据结构,它遵循先进先出(First-In-First-Out,FIFO)的原则。队列通常表示为一个有序的元素列表,新的元素被添加到队列的末尾,而从队列中删除元素时,总是从队列的开头移除。
队列的操作包括两个主要部分:入队(enqueue)和出队(dequeue)。
- 入队:将新的元素添加到队列的末尾。
- 出队:从队列的开头移除并返回元素。
其他常见的队列操作包括:
- 队列大小(size):返回当前队列中的元素个数。
- 队列是否为空(isEmpty):检查队列是否没有任何元素。
- 队列的头部元素(front):返回队列的第一个元素,而不进行出队操作。
- 清空队列(clear):移除队列中的所有元素,使其变为空队列。
队列oj题
例一:队列实现栈
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;//头
QNode* _rear;//尾
}Queue;
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
void QueueInit(Queue* q)
{
q->_front = q->_rear = NULL;
}
void QueuePush(Queue* q, QDataType data)
{
QNode* newnode = (QNode*)malloc(sizeof(QNode));
newnode->_data = data;
newnode->_next = NULL;
if (q->_rear == NULL)
{
q->_front = q->_rear = newnode;
}
else
{
q->_rear->_next = newnode;
q->_rear = newnode;
}
}
void QueuePop(Queue* q)
{
if (q->_front->_next == NULL)
{
free(q->_front);
q->_front = q->_rear = NULL;
}
else
{
QNode* tmp = q->_front->_next;
free(q->_front);
q->_front = tmp;
}
}
QDataType QueueFront(Queue* q)
{
return q->_front->_data;
}
QDataType QueueBack(Queue* q)
{
return q->_rear->_data;
}
int QueueSize(Queue* q)
{
QNode* head = q->_front;
int size = 0;
while (head)
{
head = head->_next;
size++;
}
return size;
}
int QueueEmpty(Queue* q)
{
return q->_front == NULL;
}
void QueueDestroy(Queue* q)
{
QNode* head = q->_front;
while (head)
{
QNode* next = head->_next;
free(head);
head = next;
}
q->_front = q->_rear = NULL;
}
MyStack* myStackCreate()
{
MyStack* _st=(MyStack* )malloc(sizeof(MyStack));
QueueInit(&_st->q1);
QueueInit(&_st->q2);
return _st;
}
void myStackPush(MyStack* obj, int x)
{
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj)
{//预设q1为空
Queue* empty =&obj->q1;
Queue* fall=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
empty=&obj->q2;
fall=&obj->q1;
}
//将非空队列中的最后一个数前的所有元素导入空队列中
while(QueueSize(fall)>1)
{
QueuePush(empty, QueueFront(fall));
QueuePop(fall);
}
int top=QueueFront(fall);
QueuePop(fall);
return top;
}
int myStackTop(MyStack* obj)
{
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj)
{
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(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);
*/
代码思路简述:目标栈含有两个队列,为了符合栈先入先出的性质,所以使用两队列互相移动数据。数据进入非空队列,出队列为非空队列的前n-1个数据,腾挪至另一个空队列,然后只剩1个数据的队列出数据,即可做到先入后出。
例二:栈实现队列
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
typedef struct
{
ST s1;
ST s2;
} MyQueue;
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
// 11:40
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps)
{
assert(ps);
//
assert(ps->top > 0);
--ps->top;
}
STDataType STTop(ST* ps)
{
assert(ps);
//
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
MyQueue* myQueueCreate()
{
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
STInit(&obj->s1);
STInit(&obj->s2);
return obj;
}
void myQueuePush(MyQueue* obj, int x)
{
STPush(&obj->s1, x);
}
int myQueuePeek(MyQueue* obj)
{
if (STEmpty(&obj->s2))
{
while (!(STEmpty(&obj->s1)))
{
STPush(&obj->s2, STTop(&obj->s1));
STPop(&obj->s1);
}
}
return STTop(&obj->s2);
}
int myQueuePop(MyQueue* obj)
{
int fount = myQueuePeek(obj);
STPop(&obj->s2);
return fount;
}
bool myQueueEmpty(MyQueue* obj)
{
return STEmpty(&obj->s1) && STEmpty(&obj->s2);
}
void myQueueFree(MyQueue* obj)
{
STDestroy(&obj->s2);
STDestroy(&obj->s1);
free(obj);
obj = NULL;
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/
解题思路:为实现队列的先入先出,需要两个栈,数据先入栈,再将含有数据栈的n个数据出栈,达到数据倒置的效果,再将数据栈出栈,达到先入先出的效果
例三:设计循环队列
typedef struct {
int *a;
int front ;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue *obj=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
obj->a=(int *)malloc(sizeof(int)*(k+1));
obj->front=obj->rear=0;
obj->k=k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->front==obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->k+1)==obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear]=value;
obj->rear++;
obj->rear%=(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj) )
return false;
++obj->front;
obj->front%=(obj->k+1);
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
return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
/**
* Your MyCircularQueue struct will be instantiated and called as such:
* MyCircularQueue* obj = myCircularQueueCreate(k);
* bool param_1 = myCircularQueueEnQueue(obj, value);
* bool param_2 = myCircularQueueDeQueue(obj);
* int param_3 = myCircularQueueFront(obj);
* int param_4 = myCircularQueueRear(obj);
* bool param_5 = myCircularQueueIsEmpty(obj);
* bool param_6 = myCircularQueueIsFull(obj);
* myCircularQueueFree(obj);
*/
注意点:队列大小需+1,用作循环。数组尾部数据下标特殊大小处理:rear%=(k+1)
取余可使尾部下标达到循环的效果。