队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列的实现,其实和栈差不多,数组和链表都可以实现,但是由于队列的特殊性,先进先出的这种特性,当我们用数组的时候,出队的时候时间复杂度会一直是O(n),
我们用单链表实现的话
@[TOC](
#define _CRT_SECURE_NO_WARNING
#pragma once
#include
#include
#include
#include
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* front;
QueueNode* rear;
}Queue;
void QueueInit(Queue* ps);//队列的初始化
void QueueDestory(Queue* ps);//队列的销毁
void QueuePush(Queue* ps,QDataType x);//入队
void QueuePop(Queue* ps);//出队
bool QueueEmpty(Queue* ps);//判断队列是否为空
size_t QueueSize(Queue* ps);//返回队列中元素的个数
QDataType QueueFront(Queue* ps);//返回队头元素
QDataType QueueRear(Queue* ps);//返回队尾元素
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
void QueueInit(Queue* ps)//队列的初始化
{
assert(ps);//如果储存指针的地址都为空的话,肯定是错误的
//刚开始的头指针与尾指针肯定是相等的,并且都是NULL
ps->front = ps->rear = NULL;
}
void QueueDestory(Queue* ps)//队列的销毁
{
assert(ps);
QueueNode* cur = ps->front;
while (cur)
{
QueueNode* ret = cur->next;
free(cur);
cur = ret;
}
ps->front = ps->rear = NULL;
}
void QueuePush(Queue* ps, QDataType x)//入队
{
assert(ps);//入队肯定是与尾指针rear有关的 先申请一个空间
QueueNode* cur = (QueueNode*)malloc(sizeof(QueueNode));
if (cur == NULL)
{
printf("malloc fail\n");
exit(-1);
}
cur->data = x;
cur->next = NULL;
/* QueueNode* ret = ps->rear->next;
ps->rear = cur;这样写的话很有问题,没有判断当两个指针都为空指针的情况
ps->rear = ret;*/
if (ps->rear == NULL)
{
assert(ps->front == NULL);//当尾指针为空的时候,头指针不可能不为空
ps->front = ps->rear = cur;
}
else
{
ps->rear->next = cur;
ps->rear = cur;
}
}
void QueuePop(Queue* ps)//出队
{
assert(ps);//出队也是头删
assert(ps->front != NULL);//如果头指针为空的话肯定是错误的
//队列中只有一个结点
if (ps->front == ps->rear)
ps->front = ps->rear = NULL;
else
{
//ps->front = ps->front->next;这样写的话涉及到内存泄露
QueueNode* ret = ps->front->next;
free(ps->front);
ps->front = ret;//这样写的话就不会涉及到什么内存泄露啦
}
}
bool QueueEmpty(Queue* ps)//判断队列是否为空
{
assert(ps);
//当头指针为空的时候,队列就是空的
return ps->front == NULL;
}
size_t QueueSize(Queue* ps)//返回队列中元素的个数
{
assert(ps);
int sum = 0;
QueueNode* cur = ps->front;
while (cur)
{
sum++;
cur = cur->next;
}
return sum;
}
QDataType QueueFront(Queue* ps)//返回队头元素
{
assert(ps);
assert(ps->front != NULL);
return ps->front->data;
}
QDataType QueueRear(Queue* ps)//返回队尾元素
{
assert(ps);
assert(ps->rear != NULL);
return ps->rear->data;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
int main()
{
Queue st;
QueueInit(&st);
QueuePush(&st, 1);
QueuePush(&st, 2323);
QueuePush(&st, 86);
QueuePush(&st, 567);
QueuePush(&st, 999);
QueuePush(&st, 666);
//printf("%d", QueueSize(&st));
while (!QueueEmpty(&st))
{
printf("%-7d", QueueFront(&st));
printf("%-7d", QueueRear(&st));
printf("%d\n", QueueSize(&st));
QueuePop(&st);
}
return 0;
}
用队列实现栈
上面就是这道题的思路了,有一说一,C语言实现这个实在是麻烦,但是我们现在用C语言写还是可以加深一下对这个结构的感觉的
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* front;
QueueNode* rear;
}Queue;
void QueueInit(Queue* ps)//队列的初始化
{
assert(ps);//如果储存指针的地址都为空的话,肯定是错误的
//刚开始的头指针与尾指针肯定是相等的,并且都是NULL
ps->front = ps->rear = NULL;
}
void QueueDestory(Queue* ps)//队列的销毁
{
assert(ps);
QueueNode* cur = ps->front;
while (cur)
{
QueueNode* ret = cur->next;
free(cur);
cur = ret;
}
ps->front = ps->rear = NULL;
}
void QueuePush(Queue* ps, QDataType x)//入队
{
assert(ps);//入队肯定是与尾指针rear有关的 先申请一个空间
QueueNode* cur = (QueueNode*)malloc(sizeof(QueueNode));
if (cur == NULL)
{
printf("malloc fail\n");
exit(-1);
}
cur->data = x;
cur->next = NULL;
/* QueueNode* ret = ps->rear->next;
ps->rear = cur;这样写的话很有问题,没有判断当两个指针都为空指针的情况
ps->rear = ret;*/
if (ps->rear == NULL)
{
assert(ps->front == NULL);//当尾指针为空的时候,头指针不可能不为空
ps->front = ps->rear = cur;
}
else
{
ps->rear->next = cur;
ps->rear = cur;
}
}
void QueuePop(Queue* ps)//出队
{
assert(ps);//出队也是头删
assert(ps->front&&ps->rear);//如果头指针为空的话肯定是错误的
//队列中只有一个结点
if (ps->front->next == NULL)
{
free(ps->front);
ps->front = ps->rear = NULL;
}
else
{
//ps->front = ps->front->next;这样写的话涉及到内存泄露
QueueNode* ret = ps->front->next;
free(ps->front);
ps->front = ret;//这样写的话就不会涉及到什么内存泄露啦
}
}
bool QueueEmpty(Queue* ps)//判断队列是否为空
{
assert(ps);
//当头指针为空的时候,队列就是空的
return ps->front == NULL;
}
size_t QueueSize(Queue* ps)//返回队列中元素的个数
{
assert(ps);
int sum = 0;
QueueNode* cur = ps->front;
while (cur)
{
sum++;
cur = cur->next;
}
return sum;
}
QDataType QueueFront(Queue* ps)//返回队头元素
{
assert(ps);
assert(ps->front != NULL);
return ps->front->data;
}
QDataType QueueRear(Queue* ps)//返回队尾元素
{
assert(ps);
assert(ps->rear != NULL);
return ps->rear->data;
}
typedef struct {
Queue st1;
Queue st2;
} MyStack;
MyStack* myStackCreate() {
MyStack*obj = (MyStack*)malloc(sizeof(MyStack));
assert(obj);
QueueInit(&(obj->st1));
QueueInit(&(obj->st2));//这边一定不能忘记初始化
return obj;
}
void myStackPush(MyStack* obj, int x) {
assert(obj);
// if(obj->st1->front==NULL) obj->st1是一个队列,不是指针
if(QueueEmpty(&(obj->st1)))
{
QueuePush(&(obj->st2),x);
}
else
{
QueuePush(&(obj->st1),x);
}
}
int myStackPop(MyStack* obj) {
assert(obj);
//这部分是一个小技巧,通过一个简单的操作使得无论哪个队列为空,我们需要操作的都是
//一样的 避免了代码的重复性
Queue*noEmpty = &(obj->st1);
Queue*Empty = &(obj->st2);
if(QueueEmpty(&obj->st1))//题目要注意的是传进去的都是地址,千万不要忘记取地址了
{
noEmpty = &(obj->st2);
Empty = &(obj->st1);
}
while(QueueSize(noEmpty)>1)
{
QueuePush(Empty,QueueFront(noEmpty));
QueuePop(noEmpty);
}
int ret = QueueFront(noEmpty);
QueuePop(noEmpty);
return ret;
}
int myStackTop(MyStack* obj) {
assert(obj);
if(QueueEmpty(&(obj->st1)))
{
return QueueRear(&(obj->st2));
}
else
return QueueRear(&(obj->st1));
}
bool myStackEmpty(MyStack* obj) {
assert(obj);
return QueueEmpty(&(obj->st1))&&QueueEmpty(&(obj->st2));
}
void myStackFree(MyStack* obj) {
assert(obj);
QueueDestory(&(obj->st2));
QueueEmpty(&(obj->st1));
free(obj);
}
坚持就是胜利!
用栈实现队列
**注意:**一定得保持一个栈始终有数字,另外一个栈始终没有数字,这样写代码的时候方便很多!
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶的位置
int capacity;//容量
}ST;
void StackInit(ST* ps)//栈的初始化
{
assert(ps);//栈可以为空,但是储存栈的结构体不可能是空的
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void StackDestory(ST* ps)//栈的销毁
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void StackPush(ST* ps, STDataType x)//压栈
{
assert(ps);
//压栈之前要检查一下栈是否满 因为我们的top始终是位于栈顶的下一个位置
//所以当top的值等于capacity的时候栈就满了或者是一开始栈空的情况
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->a = (ST*)realloc(ps->a, sizeof(ST) * newCapacity);//在原来的基础上扩容,所以用realloc
if (ps->a == NULL)
{
printf("malloc fail\n");
exit(-1);
}
ps->capacity = newCapacity;
}
//压栈
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)//出栈
{
assert(ps);
//出栈之前要考虑一下栈是否为空,空的话就不用出栈了 所以还需要一个断言
assert(ps->top > 0);
ps->top--;//因为我们打印的时候是从头开始遍历的,只会遍历到top所以只需要top--
}
bool StackEmpty(ST* ps)//检测栈是否为空
{
assert(ps);
//如果top = 0的时候就是栈空 所以
return ps->top == 0;
}
int StackSize(ST* ps)//返回栈中元素的个数
{
assert(ps);
return ps->top;
}
STDataType StackTop(ST* ps)//返回栈顶的元素
{
assert(ps);//同时这里要确保栈中不为空
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
typedef struct {
ST s1;
ST s2;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue*cur = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&cur->s1);
StackInit(&cur->s2);
return cur;
}
//始终保持s1有数字
void myQueuePush(MyQueue* obj, int x) {
assert(obj);
StackPush(&obj->s1,x);
}
int myQueuePop(MyQueue* obj) {
assert(obj);
while(StackSize(&obj->s1)>1)
{
StackPush(&obj->s2,StackTop(&obj->s1));
StackPop(&obj->s1);
}
int ret = StackTop(&obj->s1);
StackPop(&obj->s1);
while(StackSize(&obj->s2)>0)
{
StackPush(&obj->s1,StackTop(&obj->s2));
StackPop(&obj->s2);
}
return ret;
}
int myQueuePeek(MyQueue* obj) {
assert(obj);
ST*cur = &obj->s1;
return cur->a[0];//队列的开头也就是栈底 栈底也就是a[0];
}
bool myQueueEmpty(MyQueue* obj) {
assert(obj);
return StackEmpty(&obj->s1);
}
void myQueueFree(MyQueue* obj) {
assert(obj);
StackDestory(&obj->s1);//摧毁的时候一定要分别free,因为free只会消除其指向的
//空间
StackDestory(&obj->s2);
free(obj);
}
/**
* 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);
*/
循环队列
我们先看下循环队列大致是怎样的,然后思考一下我们怎样去实现它
可以看出 用数组或者是循环单链表都是可以的,但是单链表要考虑的东西有点多,我在这就用数组实现一下
typedef struct {
int *a;
int front;
int rear;
int k;//表示循环队列的长度为k但是有效长度为k-1 因为rear+1==front是判断队列满的条件
} MyCircularQueue;
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue*cur = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
cur->a = (int*)malloc(sizeof(int)*(k+1));
cur->front = 0;
cur->rear = 0;//我们代码设置的是rear初始值虽然是0
//但是随着数据入队列,rear始终在最后一个数字的下一位,同时为了方便
//判断队列空和满,我们必须留一个位置 //同时rear与front的值我们必须//记住取模
cur->k = k+1;
return cur;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
assert(obj);//入队之前要判断一下队是否满了
if(myCircularQueueIsFull(obj))
return false;
else
{
obj->a[obj->rear] = value;
obj->rear = (obj->rear+1)%(obj->k);
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
assert(obj);
//需要判断队列是否为空
if(myCircularQueueIsEmpty(obj))
return false;
else
{
obj->front = (obj->front+1)%(obj->k);
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj) {
assert(obj);
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
if (obj->rear == 0)
return obj->a[obj->k-1];
return obj->a[obj->rear - 1];//这边要注意一下 当这个rear值为0的时候呢?
//此时-1的话就会造成越界访问,所以应该加上第二个判定条件
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
assert(obj);
return obj->front==obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
assert(obj);
return ((obj->rear+1)%(obj->k))==obj->front;
}
void myCircularQueueFree(MyCircularQueue* obj) {
assert(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);
*/