目录
习题1 用队列实现栈
队列的实现
通过队列实现栈
结构体的建立
初始化
压栈
出栈
返回栈顶
判断是否为空
销毁空间
用队列实现栈
栈的实现
结构体创建
结构体的初始化
元素入队
将Push元素倒到Pop中
返回头元素然后移除
返回头元素
判断是否为空
空间的销毁
设计循环队列
结构体的定义
初始化
判断是否为空
判断是否满了
在队列内插入元素
删除队列内元素
返回队首元素
获得队尾元素
空间释放
225. 用队列实现栈 - 力扣(LeetCode)
1.把有数据队列的内容,传到没数据的队列中,传一个之后,再原队列中删一个
2.等q1中剩一个元素的时候,让这个元素出队
这样就可以达到栈的效果,1,2,3,4,5,让5先出栈,之后再按照同样的方法把q1看作空(压栈的时候要往有元素的队里压),开始倒数据即可
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode *head;
QNode* tail;
size_t size;
}Queue;
void QueueInit(Queue* pq);
void QueueDestory(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 QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
del = NULL;
}
pq->head = pq->tail = NULL;
}
void QueuePush(Queue* pq, QDataType x)
{
QNode* newnode = (QNode*)malloc(sizeof(QNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = pq->tail->next;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}//如果只剩一个节点,单独处理,防止tail变为野指针
else
{
QNode* cur = pq->head;
pq->head = pq->head->next;
free(cur);
cur = 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)
{
return pq->size;
}
typedef struct {
Queue q1; //建立俩个
Queue q2;
} MyStack;
//也可用Queue*,但是这样的话要用malloc给q1和q2开辟空间
MyStack* myStackCreate() {
MyStack*obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}//直接传参即可
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}//如果q1不是空,把元素压到q1
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
Queue *empty=&obj->q1;//假设q1为空
Queue *noempty=&obj->q2;//假设q2不是空
if(!QueueEmpty(&obj->q1))
{
noempty=&obj->q1;
empty=&obj->q2;
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->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) { QueueDestory(&obj->q1); QueueDestory(&obj->q2); free(obj); }
这里不能直接free(obj),因为q1和q2是链表,链表的内存不连续,如果释放掉boj,则q1和q2没有释放,会造成内存泄漏
232. 用栈实现队列 - 力扣(LeetCode)
若队列中是1 2 3 4 5,则按照栈的规则,此时出栈顺序应该是 5 4 3 2 1,我们可以用俩个队列来实现栈
1.把PushST里面的数据倒到PopST
2.出栈的时候,我们只需要出PopST里面的元素就可以,当有元素要填充时,填充到PushST就行
typedef int STDdtaTtype;
typedef struct Stcak
{
STDdtaTtype* data;
int top;
int capacity;
}ST;
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps, STDdtaTtype x);
void StackPop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
STDdtaTtype StackTop(ST* ps);
void StackInit(ST* ps)
{
assert(ps);
ps->data = NULL;
ps->capacity = ps->top = 0;
}
void StackDestory(ST* ps)
{
assert(ps);
free(ps->data);
ps->capacity = ps->top = 0;
ps->data = NULL;
}
void StackPush(ST* ps, STDdtaTtype x)//注意要看top的位置是0还是-1
{
assert(ps);
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
if (ps->capacity == ps->top)//判断是否满了
{
STDdtaTtype* tmp = realloc(ps->data, sizeof(ps) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->data = tmp;
ps->capacity = newcapacity;
}
ps->data[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
--ps->top;
}
STDdtaTtype StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->data[ps->top - 1];
}
bool StackEmpty(ST* ps)//判断是否为空栈
{
assert(ps);
return ps->top == 0;
}
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
typedef struct {
ST PushST;
ST 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);
}
void PushSTTOPopsT(MyQueue* obj)
{
if(StackEmpty(&obj->PopST))//如果Pop栈内为空,并且Push不为空就给元素
{
while(!StackEmpty(&obj->PushST))//当Push不为空
{
StackPush(&obj->PopST,StackTop(&obj->PushST));
StackPop(&obj->PushST);
}
}
}
int myQueuePop(MyQueue* obj) {
PushSTTOPopsT(obj);
int front=StackTop(&obj->PopST);
StackPop(&obj->PopST);
return front;
}
int myQueuePeek(MyQueue* obj) {
PushSTTOPopsT(obj);
return StackTop(&obj->PopST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->PopST)&&StackEmpty(&obj->PushST);
}
void myQueueFree(MyQueue* obj) {
StackDestory(&obj->PushST);
StackDestory(&obj->PopST);
free(obj);
}
622. 设计循环队列 - 力扣(LeetCode)
这里采用数组实现(链表有缺点后面会讲到),front指向首元素,back指向最后元素的下一个空间,空间大小为4,多开辟一个空间,即总共开辟五个空间,使得back+1的位置是front
typedef struct {
int *a;
int front;
int back;
int N; //用来统计空间的总个数
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int *)malloc(sizeof(int)*(k+1)); //多开辟一个空间
obj->back=obj->front=0;
obj->N=k+1;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->back==obj->front;
}//当back==front时,就是空
元素满了之后back指向红框,back+1,back指向数组外,此时让back%N,back就会回到首元素位置
bool myCircularQueueIsFull(MyCircularQueue* obj) { return (obj->back+1)%obj->N==obj->front; }//当back的下一个位置是front时候是满
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { if (myCircularQueueIsFull(obj)) return false; //如果满了则退出 obj->a[obj->back]=value; obj->back=(obj->back+1)%obj->N; //插入之后,back要走到下一个位置 return true; }
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front=obj->front%obj->N; //跟back一样,要防止越界
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->back-1+obj->N)%obj->N]; }
back的上一个位置就是队尾元素,队back-1即可,但是存在一个问题
当back位于该位置时,back-1就是-1,此时我们可以(back-1+N)%N,使back回到最后一个位置,不用链表实现该题是因为,当获取back所在元素时,链表需要遍历,而数组可以直接访问
小练习题:
5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N-1。其队内有效长度为?(假设 队头不存放数据)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C ear - front) % (N + 1)
D (rear - front + N) % (N - 1)
选B,
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a); //先释放数组空间,再释放给结构体创建的空间
free(obj);
}