很久没有更新博客,是因为在忙着军训。军训的日子可真不是人可以过的呀,好在扛了过来,但是还是落下了很多知识点。一定要奋力直追的!
复习知识点:
队列先进先出,栈后进先出。
1.队列实现栈
思路:两组队列,一组队列存储数据,一组队列为空。要取出一个数据时,将存储数据的前N-1个数导入到另一组队列当中去,读取第N个数据并移除。
代码如下:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}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);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
}
pq->head = pq->tail = NULL;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
else
{
newnode->data = x;
newnode->next = NULL;
}
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
del = NULL;
}
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;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
int QueueSize(Queue* pq)
{
assert(pq);
/*QNode* cur = pq->head;
int n = 0;
while (cur)
{
++n;
cur = cur->next;
}
return n;*/
return pq->size;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate(){
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
//q1不为空
if(QueueEmpty(&obj->q1)==0)
{
QueuePush(&obj->q1,x);
}
//q1为空
else
{
QueuePush(&obj->q2,x);
}
}
//移除并返回栈顶元素
int myStackPop(MyStack* obj) {
//1.判断为空不为空队列
Queue* empty=&obj->q1;
Queue* nonempty=&obj->q2;
if(QueueEmpty(&obj->q1)==0)
{
empty=&obj->q2;
nonempty=&obj->q1;
}
//2.将不为空队列的数据导入为空数列中去
while(QueueSize(nonempty)>1)
{
QueuePush(empty,QueueFront(nonempty));
QueuePop(nonempty);
}
//3.移除并返回栈顶元素
int ret=QueueFront(nonempty);
QueuePop(nonempty);
return ret;
}
int myStackTop(MyStack* obj) {
if(QueueEmpty(&obj->q1)==0)
{
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);
}
2.栈实现队列
思路:同样用两个栈来实现队列,一个栈为pushST,用来压栈存储数据,另一个栈为popST,用来读取数据。当popST为空时,此时将pushST中的所有数据导入到popST,再来完成相应的动作。
代码如下:
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
// 支持动态增长的栈
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity= ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = data;
ps->top++;
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
return ps->a[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
typedef struct {
Stack pushST;
Stack popST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj =(MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->pushST);
StackInit(&obj->popST);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushST,x);
}
int myQueuePop(MyQueue* obj) {
PushSTToPopST(&obj->pushST,&obj->popST);
int ret=StackTop(&obj->popST);
StackPop(&obj->popST);
return ret;
}
void PushSTToPopST(Stack* pushST,Stack* popST)
{
//只有popST为空时,才将pushST中的数据全部倒过来的。
if(StackEmpty(popST)==1)
{
while(StackSize(pushST)!=0)
{
StackPush(popST,StackTop(pushST));
StackPop(pushST);
}
}
}
int myQueuePeek(MyQueue* obj) {
PushSTToPopST(&obj->pushST,&obj->popST);
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST)&&StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj);
}
3.设计循环队列
思路:重点是判断为空和为满。只凭借front与back是相等是无法判断的,因为back指向的是队尾的下一位置。此时有两种解决方案,第一种是设置size,第二种是设置额外的一块空间,判断为满的标志是back的下一位置与front是对应的。
代码如下:
//选择数组实现
typedef struct {
int* a;
int front;
int back;
int N;//这里选择用N来表示空间个数
} MyCircularQueue;
//创建并初始化
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));//通过多创建一块空间来实现判断空满问题
obj->front=obj->back=0;
obj->N=k+1;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->back;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
//根据分析得,back的下一个位置是front代表循环队列是已满状态
//数组存在边界问题
return obj->front==(obj->back+1) % obj->N;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
//不仅要进行判断,还要完成插入元素的动作
obj->a[obj->back]=value;
obj->back++;
obj->back%=obj->N;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
//不仅要进行判断,还要完成插入元素的动作
//从队列中删除元素,front是向后移动的,原来的数据并不挪动,如果要添加新的元素,则直接被覆盖
obj->front++;
obj->front %=obj->N;
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
//如果back此时代表下标1呢
//return obj->a[obj->back-1];
return obj->a[(obj->back-1+obj->N)%obj->N];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
4.有关循环队列的选择题
我的博客写的很简陋,很大一部分原因是想着写博客给自己复习。小部分原因是自己没有很多时间和精力去打理。但是你既然要认真做一件事,还是做好。不然某一天,报应就会来的。
接下来,我还欠着七篇博客要写。希望自己之后可以天天坚持来写。我的目标并不高,我只是希望自己能找到一份薪资合适的工作而已。