栈:一种特殊的线性表(顺序表),只允许在固定的一端进行插入和删除元素。(先入后出原则)
(1)压栈:在栈顶进行插入。
(2)出栈:在栈顶进行删除。
通常用顺序表的形式来实现栈,因为链表在实现尾删操作的时候要引入prev(前节点指针,会多一个变量,过程稍许复杂。)
栈中结构体成员:
typedef struct Stack {
STDataType *arr;//栈中存储数据的数组
int top; // 栈顶的下标,top-1即为栈顶元素
int capacity; //数组的总容量
}ST;
初始化栈:
//栈的初始化
void STinit(ST* ps) {
assert(ps);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
压栈:
void STPush(ST* ps, STDataType x) {
assert(ps);
//空间不足
if (ps->top == ps->capacity) {
ps = BuyStorage(ps);
}
//直接将要压栈的元素放在栈顶
ps->arr[ps->top] = x;
ps->top++;
}
出栈:
//出栈
void STPop(ST* ps) {
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
删除栈:
//栈的摧毁
void Destroy(ST* ps) {
assert(ps);
free(ps->arr);
ps->arr = NULL;//栈中元素都存入arr数组中,free掉arr首地址即可释放其中所有元素
ps->capacity = ps->top = 0;
}
队列:只允许在一端插入数据,在另一端删除数据。(先进先出原则)。
(1)入队:在队尾进行插入。
(2)出队:在队头进行删除。
通常用链表的方式来实现队列,因为队列在执行出队操作时,是从队头出的,顺序表执行头删后需要将数组后面元素整体进行前移,而链表就很好避免了这一缺点。
队列中结构体成员:
//队列中每一个节点中的成员
typedef struct Quence{
QuenDataType val;//队列中节点的数值
struct Quence* next;//节点的下一个指针
}Que;
//队列整体成员
typedef struct QuenceT {
Que* phead;//队列中头节点,方便后续输出队头元素
Que* tail;//队列中尾节点,方便后续输出队尾元素
int size;//队列的长度
}QT;
初始化队列:
void QueInit(QT* ps) {
assert(ps);
ps->phead = ps->tail = NULL;//队列头尾节点均初始化为空
ps->size = 0;
}
入队:
void QuePush(QT* ps, QuenDataType x) {
assert(ps);
if (ps->tail == NULL) {
assert(ps->phead == NULL);//防止头尾一个为空一个不为空
ps->tail = ps->phead = QBuyStorage(x);
}
else {
ps->tail->next = QBuyStorage(x);
ps->tail = ps->tail->next;//记录新的尾节点//这个地方一定不能写成ps->tail = QBuyStorage(x);不然ps->tail->next就置为空指针了
//ps->tail = BuyStorage(x);
}
ps->size++;
}
出队:
void QuePop(QT* ps) {
assert(ps);
assert(!QueEmpty(ps));//判断队列是否为空队列,是的话此处断言生效。目的是防止出现NULL->next现象
if (ps->phead->next == NULL) {
free(ps->phead);//头删
ps->phead = ps->tail = NULL;
}
else {
//头删
Que* Node = ps->phead->next;//存入新的头节点,不然旧的头节点释放后找不到新的头节点
free(ps->phead);
ps->phead = Node;
}
ps->size--;
}
删除队列:
void QueDestroy(QT* ps) {
assert(ps);
Que* cur = ps->phead;
//依次释放队列中的每一个节点,不然会内存泄漏。
while (cur) {
Que* next = cur->next;
free(cur);
cur = next;
}
ps->phead = ps->tail = NULL;
ps->size = 0;
}