一丶栈
1.栈的定义
非常简单,就是先进后出,后进先出的线性表。举个例子,弹夹装子弹,一颗一颗往下摁,然后打出去的时候就是最上面的(最后填充的)子弹。
2.图解
3.栈操作
(1).创建栈结构
typedef int DateType;
typedef struct MyStack {
DateType* val; //元素
int top; //
int size; //容量
}ST;
这里的top有两种说法:第一,top = 0,那么top就是指向栈顶元素的下一个;第二,top = -1,那么top就指向栈顶元素。两种都行,只是对于后续操作会有些许差异,我用的是第一种。
(2).初始化
void STInit(ST* st)
{
assert(st);
st->top = 0;
st->size = 0;
st->val = NULL;
}
全部置为0或NULL。
(3).入栈
void STPush(ST* st, DateType x) // 入栈
{
assert(st);
if (st->top == st->size) //检查是否栈满
{
int newsize = st->size == 0 ? 4 : st->size * 2; //三目运算符,如果栈容量为0,就给四个单位的容量,其他情况就扩容到原来的两倍
DateType *newval = (DateType*)realloc(st->val,sizeof(DateType) * newsize);
//realloc开辟新空间
if (newval) //以防开辟空间失败
{
st->val = newval;
st->size = newsize;
newval = NULL;
}
else
{
perror("realloc fail");
return;
}
}
st->val[st->top++] = x; //插入元素
}
(4).出栈
DateType STPop(ST* st) //出栈
{
assert(st);
if (st->top > 0)
{
return st->val[--st->top];
}
return NULL;
}
前面说了,我的top指向栈顶元素的下一个(其实就是数据长度),所以先减一再元素出栈。这里可能会有一点不理解,我访问的数组下标范围是[0,top-1],此时top == 5,出栈后top == 4,5这个空间还存在,但逻辑上已经被移除,下次入栈就会覆盖5的那个空间。
(5).获取栈顶元素
DateType STTop(ST* st) //获取栈顶元素
{
assert(st);
if (st->top > 0) return st->val[st->top - 1];
return NULL;
}
(6).判空
int STEmpty(ST* st) //检查空,空返回1,非空0
{
assert(st);
if (st->top > 0) return 0;
return 1;
}
4.栈补充
栈可以数组实现也可以链表实现,个人认为数组更简单理解和实现。在程序中,栈应用得最多的就是递归操作。
二丶队列
1.队列的定义
队列是只允许在一端进行插入操作,另一端删除操作的线性表。简单来说先进先出,后进后出。听名字联想在食堂排队吃饭,一下就理解了。
2.循环队列
这里的循环队列是用数组实现的,假设此时rear 和 front 是数组下标为0的地方。队列也是可以用链式结构实现的。
插入一个数据后
此时front == 0,rear == 4,如果rear + 1就会等于5,那么数组就越界了,于是我们每次给rear 和 front 赋值的时候就采用模(取余数)的方法,rear = (rear + 1)%maxsize(数组最大容量),这样就可以将rear 和 front 的取值控制在[0,maxsize - 1],然后插入一个数据,尾指针(rear)就加1,删除一个数据头指针(front)就加1,如上图图二,当(rear + 1) % maxsize == front {此时就是(4 + 1)% 5 == 0}的时候,此时队列就满了,虽然这个方法多出来了一个单位的空间,但是如果有上万个甚至上亿个数据,这多出来的就可以忽略不计。至于队空,如果一直出队操作,front最终会和rear相遇,此时front == rear,这就是队空。
3.队列的操作(循环队列)
(1).创建队列结构
typedef int SQDataType;
#define maxsize 5
typedef struct SqQueue {
SQDataType arr[maxsize];
int rear; //尾
int front; //头
}SQ;
依旧可以用上面栈讲的扩容方法,这里就只讲思路了。
(2).初始化
void SQInit(SQ* sq)
{
sq->front = sq->rear = 0;
}
(3).入队
void EnQueue(SQ* sq, SQDataType x) //入队
{
if ((sq->rear + 1) % maxsize == sq->front) //队满
{
printf("队满");
return;
}
sq->arr[sq->rear] = x;
sq->rear = (sq->rear + 1) % maxsize;
}
(4).出队
int DeQueue(SQ* sq) //出队
{
int temp = 0;
if (sq->front == sq->rear)
{
printf("队空\n");
}
temp = sq->arr[sq->front];
sq->front = (sq->front + 1) % maxsize;
return temp;
}