队列和栈都是数据结构中非常常见的形式,下面我们就来剖析一下这两种结构。
一.栈
首先给出我非常喜欢的一种栈的写法,这是以前从别的地方看到的
#include<stdio.h>
typedef struct tom {
int num[5];
int top; //栈顶指针,空栈时为-1;满栈时为n-1 n为数组容量
}stack;
//压栈操作
int push(stack *ca,int n)
{
if (ca->top == 4) //进行是否栈满的判断
return -1;
ca->num[ca->top + 1] = n;
ca->top++; //移动栈顶指针
return 1;
}
//出栈操作
int pop(stack *ca, int *n)
{
if (ca->top == -1) //进行是否空栈的判断
return -1;
*n = ca->num[ca->top];
ca->top--; //移动栈顶指针
return 1;
}
int main(void)
{
int n = 0;
stack ca{
{ 1,2,3 },
2
};
printf("%d\n", push(&ca, 4));
printf("%d\n", push(&ca, 5));
printf("%d\n", push(&ca, 6));
printf("%d\n", pop(&ca, &n));
printf("%d", n);
return 0;
}
特征:栈是仅在表尾进行插入和删除操作的线性表,“先进后出,后进先出”。
允许进行插入和删除操作的一端被称为栈顶,另一端称为栈尾。
栈由一个数组和栈顶指针组成,**栈顶指针**top直接显示着栈顶数据的数组下标,在压栈之前要首先进行是否栈满的判断,出栈时要判断是否空栈,特别注意,由于栈顶指针表示的是栈顶元素所在数组下标,所以空栈时栈顶指针的数值为0。简单的栈还存在许多问题,链栈的使用能够更加有效地解决问题。
二.队列
同样也给出我比较喜欢的一种队列的写法
#include<stdio.h>
typedef struct tom {
int num[5];
int front; //头指针
int rear; //尾指针
}line;
int start(line *a)
{
a->front = 0;
a->rear = 0;
return 1;
}
int jia(line *a, int n)
{
if ((a->rear + 1) % 5 == a->front) //判断队列是否满
return -1;
a->num[a->rear] = n;
a->rear = (a->rear + 1) % 5;
return 1;
}
int shan(line *a, int *n)
{
if (a->front == a->rear) //判断队列是否为空
return -1;
*n = a->num[a->front];
a->front = (a->front + 1) % 5;
return 1;
}
int length(line a)
{
return (a.rear - a.front + 5) % 5;
}
int main(void)
{
line kao;
int n, m;
printf("%d\n", start(&kao));
printf("%d\n", jia(&kao, 1));
printf("%d\n", jia(&kao, 1));
printf("%d\n", jia(&kao, 1));
printf("%d\n", jia(&kao, 1));
printf("%d\n", jia(&kao, 1));
printf("%d\n", jia(&kao, 1));
n = length(kao);
printf("\n%d\n", n);
printf("\n%d\n", shan(&kao, &m));
n = length(kao);
printf("\n%d\n", n);
}
特征:队列是一种只允许在一端进行插入操作,而在另一端进行删除操作的线性表,先进先出后进后出,允许插入的一端称为队尾,允许删除的一端成为队头
但是普通队列有个问题,就是明明队头之前还有很多空间,但是队尾指针已经到了数组末端,造成队列的一种假满,导致空间利用率极低,所以就要想办法利用这些空闲空间,所以要引入循环队列。
循环队列:队列的这种头尾相接的顺序存储结构称为循环队列。
这里所用的是循环队列。
队列这里主要有几个公式需要记住:
1.队列满的条件 (尾指针+1)%数组最大下标==头指针
2.计算队列长度公式 (尾指针-头指针+数组最大下标)%数组最大下标
a->rear = (a->rear + 1) % 5 这种指针的移动方法非常好。