栈
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做出栈。出数据也在栈顶。
后进先出
typedef int STDataType;
typedef struct Stack
{
STDataType* a; // 存储数据的空间
int top; // 栈中已存储元素个数, 总是指向栈位, 取栈顶元素时, 假设共有3元素, 即a[2] --- a[top - 1]
int capacity; // 栈总内存大小(最大可存储的元素个数)
}ST;
常见函数接口实现
// 初始化栈
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->top = 0;
pst->capacity = 0;
}
// 判断栈中是否还有元素
bool STEmpty(ST* pst)
{
return pst->top == 0;
}
// 压栈, 向栈中存数据
void STPush(ST* pst, STDatatype x)
{
assert(pst); // 判断指针不是NULL
if(pst->top == pst->capacity) // 先判断栈是否空间已满, 已满则重新开辟空间
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
// 有可能第一次开辟空间, 第一次开辟空间固定给4, 直接使用pst->capacity * 2得到的还是0, 所以特殊处理
pst->tem = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if(tem == NULL)
{
perror("realloc fail");
return;
}
pst->a = tem; // 指向新的空间
pst->capacity = newcapacity; // 更新总空间大小
}
}
// 出栈, 出数据
void STPop(ST* pst)
{
assert(pst); // 判断指针不是NULL
assert(!STEmpty(pst)); // 栈内还有元素
pst->top--;
// 伪删除, 因为我们只能通过top取栈顶元素, 只要top--, 那么需要删除的数据就不会再被访问了, 相当于被删除了
}
// 销毁栈, 栈使用完之后, 需要将空间释放, 否则会造成空间泄露
void STDestroy(ST* pst)
{
pst->a = pst->capacity = 0;
free(pst->a);
pst->a = NULL;
}
// 获取栈顶数据
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty)
return pst->a[pst->top - 1];
}
// 获取栈的已存储数据的数量
int STStize(ST* pst)
{
assert(pst);
return pst->top;
}
队列
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
先进先出
队列:结构体实现
typedef int QDataType;
typedef struce QueueNode // 队列的节点
{
struct QueueNode* next;
QDataType data;
}QNode;
struct Queue // 队列
{
QNode* phead; // 队头节点
QNode* tail; // 队尾节点
int size; // 队列的长度
};
常见函数接口实现
// 队列的初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->tail = NULL;
pq->size = 0;
}
// 队列的销毁, 使用完队列之后, 需要将空间释放还给操作系统, 一面造成内存泄漏
void QueueDestroy(Queue* pq)
{
assert(pq); // 确保队列合法
Qnode* cur = pq->phead;
while(cur)
{
Qnode* next = cur->next; // 这里需要先记录下一个节点, 如果先执行free, 那么下一个节点就找不到了
free(cur);
cur = next;
}
pq->phead = pq->tail = NULL;
pq->size = 0;
}
// 入队
void QueuePuhs(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode)); // 先创建出新节点
if(newnode == NULL)
{
perror("malloc fail\n");
return;
}
newnode->data = x;
newnode->next = NULL; // 完成新节点的数据初始化
if(pq->tail == NULL) // 如果队列在插入之前为空, 那么就需要将头尾指针都改变
{
assert(pq->phead == NULL);
pq->phead = pq->tail = newnode;
}
else
{
pq->tail->next = newnode; // 队列插入之前不为空, 只需要改变尾指针
qp->tail = newnode;
}
pq->size++; // 队列长度增加
}
// 判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
// 出队
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if(pq->phead->next == NULL) // 判断列表是否只有这一个数据, 如果只有这一个数据, 那么同样需要同时改变头尾指针
{
free(pq->next);
pq->phead = pq->tail = NULL;
}
else
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
// 获取队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}