目录
前言:通过前面的顺序表,链表的学习,这里的栈和队列会很简单,用的都是上面两种数据结构。
所以这里就把栈和队列放在一起来说。
一.栈具体实现
这个栈是使用动态顺序表来实现的,相对于使用链表要更好一些,当然也可以使用链表。
1.创建结构体
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶的位置
int capacity;//容量
}ST;
动态顺序表标配,只是这里用top来代替size,top就相当于栈顶。
2.初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
也是顺序表正常操作。
3.销毁栈
void StackDestory(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
与顺序表一样。
4.入栈
void StackPush(ST *ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity = newCapacity;
}
}
ps->a[ps->top] = x;
++ps->top;
}
这里因为栈只能在后面进,所以这里只有尾插,并且判断是否扩容也直接写在该函数里了。
如果ps->top == ps->capacity的时候就说明需要再次开辟空间(即扩容),这时定义一个新的newCapacity,然后通过realloc去进行扩容。
最后再把数据插入进去,并且++ps->top。
5.出栈
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
--ps->top;
}
直接--ps->top即可。
6.判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
判断ps->top == 0,如果为0,说明为空,返回1,如果不为0,说明不为空,返回0.
7.计算栈中数据个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
ps->top的值即为数据个数
8.栈顶数据
STDataType StackTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
首先这个栈里要有数据,所以断言assert(ps->top > 0)
然后当前栈顶的数据就为ps->a[ps->top - 1],因为是数组,所以要-1。
二.队列具体实现
这个队列是使用链表来实现的,相对于使用顺序表要更好一些,当然也可以使用顺序表。
1.创建结构体
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
以单链表为基础来实现,因为队列只要尾插和头删,所以可以通过再定义一个结构体,来保存这个头和尾,以实现时间复杂度为O(1)的队列。
2.初始化队列
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
要把head和tail置NULL。
3.销毁队列
void QueueDestorty(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = NULL;
pq->tail = NULL;
}
循环链表,分别进行free,然后通过next找到下一个节点的地址,继续循环,最后再把定义的pq->head和pq->tail置NULL。
4.入队列
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
assert(pq->head == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
创建新节点,然后进行分情况讨论。
当链表中没有节点时,我们分为一种情况,就是当tail和head都为空时,我们让这个tail和head都等于这个新节点,然后head就一直为该节点当做头节点,然后tail根据尾插的节点个数进行移动。
5.出队列
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head && pq->tail);
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
出队列,也要分为两种情况,一种是只剩一个head头节点时,另一种时正常情况多个节点时。
当只有一个头节点时,即pq->head->next = NULL,这时候我们直接free掉head,然后把这个head和tail都置NULL。
而正常情况,就创建一个next来保存头节点的下一个节点的地址,然后free掉头节点,并让原本头节点的下一个节点变成新的头节点。
6.判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
如果头节点为空,则说明为空。
7.计算队列数据个数
size_t QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
++size;
cur = cur->next;
}
return size;
}
遍历链表,每有一个节点,就++size,最后返回size的值。
8.队列头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
头节点的数据则为队列头数据。
9.队列尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
尾节点的数据则为尾节点数据。
三.栈代码
1.Stack.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;//栈顶的位置
int capacity;//容量
}ST;
void StackInit(ST* ps);//初始化栈
void StackDestory(ST* ps);//销毁栈
void StackPush(ST* ps, STDataType x);//入栈
void StackPop(ST* ps);//出栈
bool StackEmpty(ST* ps);//判断栈是否为空
int StackSize(ST* ps);//栈中数据个数
STDataType StackTop(ST* ps);//栈顶数据
2.Stack.c
#include "Stack.h"
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 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);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity = newCapacity;
}
}
ps->a[ps->top] = x;
++ps->top;
}
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
--ps->top;
}
bool StackEmpty(ST* ps)
{
assert(ps);
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];
}
3.Test.c
#include "Stack.h"
void TestStack()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
printf("%d ", StackTop(&st));
StackPop(&st);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
StackPush(&st, 6);
StackPush(&st, 7);
StackPush(&st, 8);
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
printf("\n");
StackDestory(&st);
}
int main()
{
TestStack();
return 0;
}
四.队列代码
1.Queue.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
void QueueInit(Queue* pq);//初始化队列
void QueueDestory(Queue* pq);//销毁队列
void QueuePush(Queue* pq, QDataType x);//入队列
void QueuePop(Queue* pq);//出队列
bool QueueEmpty(Queue* pq);//判断队列是否为空
size_t QueueSize(Queue* pq);//队列数据个数
QDataType QueueFront(Queue* pq);//队列头数据
QDataType QueueBack(Queue* pq);//队列尾数据
2.Queue.c
#include "Queue.h"
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
void QueueDestorty(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = NULL;
pq->tail = NULL;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
assert(pq->head == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head && pq->tail);
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
size_t QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
++size;
cur = cur->next;
}
return size;
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
3.Test.c
#include "Queue.h"
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
printf("%d ", QueueFront(&q));
QueuePop(&q);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
QueuePush(&q, 8);
QueuePush(&q, 9);
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
}
int main()
{
TestQueue();
return 0;
}