目录
栈
栈的概念
栈的实现
栈的实现分为两种
顺序栈和链栈的区别
代码实现(接口声明)
代码实现(接口定义)
测试
队列
队列的概念
队列的实现
队列的实现
队列的实现分为两种
代码实现(接口声明)
代码实现(接口定义)
测试
循环队列
栈:是一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做 进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈,出数据也在栈顶。
1.顺序栈 (用数组/顺序表实现)
2.链栈(用链表实现)
顺序表和链表都可以用来实现栈,一般使用顺序表,因为栈相当于阉割版的顺序表,只用了顺序表的尾插和尾删操作,顺序表的尾插和尾删不需要移动元素,效率非常高。如果是链表实现栈,一般需要进行链表头插或者头删操作,这一对比,链表的操作比顺序表复杂,因此顺序表实现栈更简单。
链栈和顺序栈的相比,比较明显的优势是不需要扩容;链式结构实现栈,每次入栈相当于链表头插一个结点,没有扩容一说。
#include
#include
#include
#include
//定义栈中的元素数据类型
typedef int SLDataType;
//支持动态增长的栈
typedef struct Stack
{
int* a;
int top; //栈顶元素的下一个位置
int capacity; //栈容量
}ST;
//栈初始化
void STInit(ST* ps);
//栈销毁
void STDestory(ST* ps);
//压栈
void STPush(ST* ps, SLDataType x);
//出栈
void STPop(ST* ps);
//栈元素个数统计
int STSize(ST* ps);
//判断栈中元素是否为空
bool STEmpty(ST* ps);
//获取栈顶元素
SLDataType STTop(ST* ps);
1.栈初始化
void STInit(ST* ps)
{
assert(ps);
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
ps->top = 0;//top是栈顶元素的下一个位置
//ps->top = -1; top是栈顶元素的的位置
ps->capacity = 4;
}
2.栈销毁
void STDestory(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
3.压栈
void STPush(ST* ps, SLDataType x)
{
assert(ps);
if (ps->top == ps->capacity) {
SLDataType* tmp = (SLDataType*)realloc(ps->a,2*ps->capacity*sizeof(SLDataType));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
4.出栈
void STPop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
5.访问栈顶元素
SLDataType STTop(ST* ps)
{
assert(ps);
return ps->a[ps->top - 1];
}
6.获取栈中有效数据元素的个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
7.判断栈中元素个数是否为空
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
int main()
{
ST st;
STInit(&st);
STPush(&st,1);
STPush(&st, 2);
STPush(&st, 3);
STPush(&st, 4);
STPush(&st, 5);
STPush(&st, 6);
while (!STEmpty(&st))
{
printf("%d->", STTop(&st));
STPop(&st);
}
printf("\n");
STDestory(&st);
return 0;
}
队列:只允许一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为 队尾
出队列:进行删除操作的一端称为 队头
队列也可以用数组(顺序表)和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列要在数组头上出数组,涉及数据挪动,效率会比较低。
#include
#include
#include
#include
//定义队列元素数据类型
typedef int QDataType;
//定义队列结点结构
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
//改变结构体的成员或者内容只需要结构体的指针
//初始化队列
void QueueInit(Queue* pq);
//销毁队列
void QueueDestory(Queue* pq);
//插入数据
void QueuePush(Queue* pq, QDataType x);
//弹出数据
void QueuePop(Queue* pq);
//队列元素个数
int QueueSize(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
//返回队列首元素
QDataType QueueFront(Queue* pq);
//返回队列尾元素
QDataType QueueBack(Queue* pq);
1.队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
2.队列销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
3.插入数据
void QueuePush(Queue* pq, QDataType x)
{
//创建新的结点
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
//插入的数据
newnode->data = x;
newnode->next = NULL;
if (pq->head == NULL) {
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else {
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
4.删除数据
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head!=NULL);
//只有一个头节点的情况
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
//不止一个结点
else {
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
5.获取队列有效数据的个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
6.获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
7.获取队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
8.判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
int main() {
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
QueuePush(&q, 8);
QueuePush(&q, 9);
while (!QueueEmpty(&q)) {
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
QueueDestory(&q);
return 0;
}
在实际中,我们也会使用一种队列叫做循环队列(环形队列),循环队列可以用数组实现,也可以有循环链表实现。
当循环队列为空时,front==rear
当循环队列满的时候,rear+1==front