栈的概念
栈是一个特殊的线性表,只允许在固定的一头进行操作,进行数据插入和删除的一头为栈顶,另一端为栈底。即入数据在栈顶,出数据也在栈顶。
栈的结构如图
栈的实现
那么栈可以用什么结构去实现呢?
其实用数组和链表去实现都可以,最佳方案用数组更好,因为数组在尾部进行尾插尾删还是很方便的,唯一缺点就是增容有空间浪费。如果用链表实现栈,插入删除数据会不方便,如果用尾做栈顶,尾加尾删会不方便,如果用尾做栈底,那么栈的插入删除就是链表的头插头删,也是可以实现栈的。
总结一下就是两种结构实现都可以,数组缓存利用率更高,数组栈稍好
头文件
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>//没引用这个头文件导致开辟形空间失败
#include<stdbool.h>
typedef int LTDataType;
typedef struct Stack
{
LTDataType* a;
int top;
int capacity;
}ST;
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps,LTDataType x);
void StackPop(ST* ps);
LTDataType StackTop(ST* ps);
int StackSize(ST* ps);
bool StackEmpty(ST* ps);
头文件的引入不要掉了,我当时就是忘记引入stdlib.h导致后面写入数据时发生了内存错误,非常难找错误
初始化
void StackInit(ST* pa)
{
assert(pa);
pa->a = NULL;
pa->top = 0;
pa->capacity= 0;
}
销毁
void StackDestory(ST* pa)
{
assert(pa);
free(pa->a);//不是freepa
pa->a = NULL;
pa->top = 0;
pa->capacity = 0;
}
pa是指针,要访问结构体指针就要用->访问
入栈
void StackPush(ST* pa,LTDataType x)
{
assert(pa);
//不知道怎么开辟新空间和将新空间判断给值
if (pa->top == pa->capacity)
{
int newcapacity =pa->capacity == 0 ? 4 : pa->capacity * 2;
LTDataType* tmp = realloc(pa->a,newcapacity*sizeof(LTDataType));
if (tmp == NULL)
{
printf("realloc fail");
exit(-1);
}
pa->a = tmp;
pa->capacity = newcapacity;
}
pa->a[pa->top] = x;
pa->top++;
}
出栈
void StackPop(ST* pa)
{
assert(pa);
assert(pa->top);
//总感觉掉个条件
pa->top--;
}
当栈为空就不能删除了
栈顶
LTDataType StackTop(ST* pa)
{
assert(pa);
assert(pa->top > 0);
//return pa->top;
return pa->a[pa->top - 1];
}
因为初始化栈顶一开始为0,这时top指向栈顶数据的下一个
判断空
bool StackEmpty(ST* pa)
{
return pa->top ==0;
}
大小
int StackSize(ST* pa)
{
assert(pa);
return pa->top;
}
打印
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
因为只能找到栈顶的数据,所以只能找到一个打印一个然后删除栈顶
队列的概念
只允许一端进另一端出的特殊线性表,具有先进先出的特性
结构如图
那么队列用什么实现比较好呢?
如果用数组去实现,当出数据时就要遍历整个结构去挪动数据,显然不方便
所以我们用链表实现,因为每次都要找尾,所以我们定义一个尾指针,那为什么单链表不也引用尾指针呢?当我们在单链表引入尾指针可以解决尾加,,但是解决不了尾删,既然解决不了所有问题,那么我们就把这个问题给了双向循环链表去解决
头文件
#pragma once
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}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);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
初始化
void QueueInit(Queue* pq)
{
pq->head = NULL;
pq->tail = NULL;
}
初始化的是头尾的指针
销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
插入
void QueuePush(Queue* pq,QDataType x)
{
assert(pq);
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
newnode->data = x;
newnode->next = NULL;
/*QueueNode* cur = pq->head;
while(cur)
{
cur = cur->next;
}
cur->next = newnode;
不用定义额外指针结构包含了头指针和尾指针*/
if (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);
QueueNode* next = pq->head->next;
free(pq->head);
pq->head = next;
if (pq->head == NULL)
{
pq->tail = NULL;
}
}
要注意如果头指针为空,第一个表达式就错了,当删到最后一个头指针时,如果不将尾指针置空,那么尾指针就指向一个不知道的空间,造成野指针
头指针的数据
QDataType QueueFront(Queue* pq)
{
return pq->head->data;
}
尾指针的数据
QDataType QueueBack(Queue* pq)
{
return pq->tail->data;
}
打印
while (!QueueEmpty(&q))
{
QDataType Front = QueueFront(&q);
printf("%d ", Front);
QueuePop(&q);
}
从头出