一、栈
概念:栈是一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。
注:出数据也在栈顶。

栈的逻辑结构是线性的,物理结构因种类而决定。
这里我们是用数组来实现栈
栈结构的实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDatatype;
typedef struct Stack {
STDatatype* arr;
int top;//指向栈顶的数据
int capacity;//栈的容量
}ST;
初始化
void STInit(ST* ps)
{
assert(ps);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
入栈--栈顶
因为栈插入数据的函数不多,所以就不单独封装增容函数了
void StackPush(ST* ps, STDatatype x)
{
//要插入数据,首先容量够不够
if (ps->top ==ps->capacity)
{
//增容
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDatatype* tmp = (STDatatype*)realloc(ps->arr, sizeof(STDatatype) * newcapacity);
if (tmp == NULL)
{
perror("realloc failed");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
ps->arr[ps->top++] = x;
}
出栈---栈顶(后入先出)
要有提前判空:
判空
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top==0;
}
void StackPop(ST* ps)
{
assert(!STEmpty(ps));
ps->top--;
}
取栈顶元素(只取不删)
STDatatype StackTop(ST* ps)
{
assert(!STEmpty(ps));
return ps->arr[ps->top - 1];
}
获取栈的有效的元素个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
销毁
void STDestory(ST* ps)
{
assert(ps);
if (ps->arr != NULL)
free(ps->arr);
ps->arr = NULL;
ps->top = ps->capacity = 0;
}
最后送一个栈的打印
void STPrint(ST* ps)
{
assert(ps && !STEmpty(ps));
/*while (!STEmpty(ps))
{
int top = StackTop(ps);
StackPop(ps);
printf("%d ", top);
}*/
for (int i = ps->top - 1; i >= 0; i--)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
注释掉的代码也是打印,更体现后入先出的逻辑,但是用一次栈的结构就会被破坏
所以小编这里还是用for循环来实现
测试代码和展示
#include"Stack.h"
void test01()
{
ST st;
STInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
StackPush(&st, 6);
int size = STSize(&st);
printf("size:%d\n", size);
STPrint(&st);
STDestory(&st);
}
int main()
{
test01();
return 0;
}

二、队列
(一)队列的概念和结构
1、概念
概念:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出。
入队列:进行插入操作的一端是队尾
出队列:进行删除操作的一端是队头
这里我们用单链表来实现队列,比较如下
1.用数组来实现,插入数据,时间复杂度O(1),删除数据,时间复杂度O(n)
2.用链表来实现,插入数据,时间复杂度O(n),删除数据,时间复杂度O(1)
3.虽然双向链表可以做到二者都为O(1),但结构复杂开辟的内存多,
4.我们可以在单链表的基础上定义一个ptail指针就能做到相同的效果进行优化
5.数组删除数据是要全部前移,不前移又会影响后面插入数据,
综上用单链表来实现
队列结构的实现
先实现结点的结构,再实现队列的结构
typedef int QDatatype;
//队列结点的结构
typedef struct Queuenode {
QDatatype data;
struct Queuenode* next;
}Queuenode;
//队列的结构
typedef struct Queue {
Queuenode* phead;
Queuenode* ptail;
}Queue;
初始化
void QueueInit(Queue* ps)
{
assert(ps);
ps->phead = ps->ptail = NULL;
}
判空
bool QueueEmpty(Queue* ps)
{
assert(ps);
return ps->phead == NULL;
}
入队----队尾
void QueuePush(Queue* ps,QDatatype x)
{
assert(ps);
//申请结点
Queuenode* newnode = (Queuenode*)malloc(sizeof(Queuenode));
newnode->data = x;
newnode->next = NULL;//新插入的结点下一个指针默认指向null
//队列为空
if (ps->phead == NULL)
{
ps->phead = ps->ptail = newnode;
}
else {
//队列不为空
ps->ptail->next = newnode;
ps->ptail = newnode;
}
}
入队要注意两种情况
1.队列为空
2.队列不为空
出队-----队头
void QueuePop(Queue* ps)
{
assert(ps && !QueueEmpty(ps));
//如果队列只有一个结点
if (ps->phead == ps->ptail)
{
free(ps->phead);
ps->phead = ps->ptail = NULL;
}
else {
Queuenode* next = ps->phead->next;
free(ps->phead);
ps->phead = next;
}
}
出数据,要先确认队列不能为空,两种情况
1.只有一个结点
2.其他情况
分开处理防止对空指针的解引用,详细见上代码
取对头数据
QDatatype QueueFront(Queue* ps)
{
assert(ps && !QueueEmpty(ps));
return ps->phead->data;
}
取队尾数据
QDatatype QueueBack(Queue* ps)
{
assert(ps && !QueueEmpty(ps));
return ps->ptail->data;
}
取队列中有效的元素
int QueueSize(Queue* ps)
{
assert(ps);
Queuenode* pcur = ps->phead;
int size = 0;
while (pcur)
{
size++;
pcur = pcur->next;
}
return size;
}
遍历队列,然后size计数器,返回size
销毁
void QueueDestory(Queue* ps)
{
assert(ps);
Queuenode* pcur = ps->phead;
while (pcur)
{
Queuenode* next = pcur->next;
free(pcur);
pcur = next;
}
ps->phead = ps->ptail = NULL;
}
销毁要遍历队列,就是遍历链表,要注意在free结点时,要提前保存其下一个结点,进行循环销毁
测试代码和展示
#include"Queue.h"
void test01()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
int x = QueueFront(&q);//获取队首元素
printf("x=%d\n", x);
int y = QueueBack(&q);//获取队尾元素
printf("y=%d\n", y);
//队列
QueueDestory(&q);//销毁队列
}
int main()
{
test01();
return 0;
}

结尾:
今天的内容就到这里了,希望大家给个三连支持一下,后续会继续更新,感谢阅读!
【封面】

4914

被折叠的 条评论
为什么被折叠?



