五十三、 顺序栈
53.1 顺序栈的概念
- 栈就是操作受限的线性表,只允许在栈顶操作的线性结构(只能在一端进行操作的线性表)
- 后进先出(LIFO)Last Out First In
- 栈的顺序实现,除了需要一个数组外,还需要一个栈顶元素的下标
(标记栈顶的元素) - 当栈中没有元素时,栈顶指针下标应该是-1;
53.2 顺序栈的结构体
#define MAX 5
typedef int data;
typedef struct seq_stack
{
// 用于存放栈元素的数组
data arr[MAX];
// 用于指向栈顶的位置
int top;
} my_stack;
53.3 顺序栈实现(接口,功能实现,测试用主函数,Makefile)
接口(head.h)
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5
typedef int data;
typedef struct seq_stack
{
// 用于存放栈元素的数组
data arr[MAX];
// 用于指向栈顶的位置
int top;
} my_stack;
// 创建栈
my_stack *init();
// 栈的判满
int is_full(my_stack *s);
// 栈的判空
int is_empty(my_stack *s);
// 压栈
int push_stack(my_stack *s, data value);
// 出栈
data pop_stack(my_stack *s);
// 遍历输出栈
int output(my_stack *s);
// 栈清空
int clear_stack(my_stack *s);
// 销毁栈
int free_stack(my_stack **s);
#endif
功能实现(my_struct.c)
#include "head.h"
// 创建栈
my_stack *init()
{
my_stack *s = (my_stack *)malloc(sizeof(my_stack));
if (NULL == s)
{
printf("创建栈失败\n");
return NULL;
}
memset(s, 0, sizeof(my_stack));
s->top = -1;
return s;
}
// 栈的判满
int is_full(my_stack *s)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (p->top == MAX - 1)
{
return 1;
}
return 0;
}
// 栈的判空
int is_empty(my_stack *s)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (p->top == -1)
{
return 1;
}
return 0;
}
// 压栈
int push_stack(my_stack *s, data value)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (!is_full(p))
{
// 栈顶指针先+1,再进行入栈,因为栈顶指针是从-1开始
p->arr[++(p->top)] = value;
return 0;
}
printf("此栈已满,不可再压栈\n");
return -1;
}
// 弹栈
data pop_stack(my_stack *s)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (!is_empty(p))
{
return p->arr[p->top--];
}
printf("此栈已空,不可再弹栈\n");
return -1;
}
// 遍历输出栈
int output(my_stack *s)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (!is_empty(p))
{
int i = p->top;
printf("从栈顶到栈底元素依次为:\n");
for (int j = 0; i >= 0; i--, j++)
{
printf("第 %d 位为: %d\n", j + 1, p->arr[i]);
}
return 0;
}
printf("此栈已空,无元素可输出\n");
return -1;
}
// 栈清空
int clear_stack(my_stack *s)
{
if (NULL == s)
{
printf("传入参数为空\n");
return -1;
}
my_stack *p = s;
if (!is_empty(p))
{
memset(p->arr, 0, sizeof(p->arr));
p->top = -1;
printf("此栈已清空\n");
return 0;
}
printf("此栈已空,不必再清空\n");
return -1;
}
// 销毁栈
int free_stack(my_stack **s)
{
if (NULL == *s)
{
printf("传入参数为空\n");
return -1;
}
free(*s);
*s = NULL;
return 0;
}
测试用主函数(main.c)
#include "head.h"
int main(int argc, char const *argv[])
{
my_stack *s = init();
push_stack(s, 12);
output(s);
push_stack(s, 21);
output(s);
push_stack(s, 32);
output(s);
push_stack(s, 23);
output(s);
push_stack(s, 13);
output(s);
push_stack(s, 31);
output(s);
push_stack(s, 33);
output(s);
pop_stack(s);
output(s);
pop_stack(s);
output(s);
clear_stack(s);
output(s);
pop_stack(s);
output(s);
push_stack(s, 99);
output(s);
return 0;
}
Makefile
EXE=mystruct
CC=gcc
CFLAGs=-c
OBJs+=my_struct.o
OBJs+=main.o
all:$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o mystruct
五十四、 链栈
54.1 链栈的概念
- 由于栈是一个操作受限的线性表,可以有顺序结构也可以由链式存储实现
- 如果想要实现链栈,其实就是链表,只能在一端操作
- 由于链表的尾插和尾删需要遍历整条链表,所以实现链栈时,通过头插和头删
54.2 链栈的结构体
栈元素结点:
// 栈元素结点
typedef struct linked_stack
{
// 元素结点的值
data value;
// 指向下一结点
struct linked_stack *next;
} linked_stack;
栈顶指针:
// 栈顶指针
typedef struct top_stack
{
// 记录栈内有多少个元素
int len;
// 指向栈顶元素结点
struct linked_stack *top;
} top_st;
54.3 压栈----链表的头插
压栈:
// 压栈
int push_stack(top_st *t, data value)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
// 创建栈结点
linked_stack *lt = (linked_stack *)malloc(sizeof(linked_stack));
if (NULL == lt)
{
printf("创建栈结点失败\n");
return -1;
}
// 栈结点填充值
lt->value = value;
// 当前栈结点接入到之前栈结点的前面
lt->next = t->top;
// 栈顶指针指向当前栈结点
t->top = lt;
++t->len;
return 0;
}
54.4 弹栈----链栈的头删
弹栈:
// 弹栈
data pop_stack(top_st *t)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(t))
{
linked_stack *p = t->top;
data value = t->top->value;
t->top = t->top->next;
free(p);
--t->len;
return 0;
}
printf("此栈已空,不可再弹栈\n");
return -1;
}
54.5 链栈的代码(接口,功能实现,测试用主函数,Makefile)
接口(head.h)
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int data;
// 栈元素结点
typedef struct linked_stack
{
data value;
struct linked_stack *next;
// struct linked_stack *top;
} linked_stack;
// 栈顶指针
typedef struct top_stack
{
int len;
struct linked_stack *top;
} top_st;
// 创建栈顶指针
top_st *create_top();
// 栈的判空
int is_empty(top_st *s);
// 压栈(头插)
int push_stack(top_st *s, data value);
// 出栈(头删)
data pop_stack(top_st *s);
// 遍历输出栈
int output(top_st *s);
// 栈清空
int clear_stack(top_st *s);
// 销毁栈
int free_stack(top_st **s);
#endif
功能实现(my_linked_struct.c)
#include "head.h"
// 创建栈顶指针
top_st *create_top()
{
top_st *t = (top_st *)malloc(sizeof(top_st));
if (NULL == t)
{
printf("创建栈顶指针失败\n");
return NULL;
}
t->len = 0;
t->top = NULL;
return t;
}
// 栈的判空
int is_empty(top_st *t)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
top_st *p = t;
if (NULL == p->top)
{
return 1;
}
return 0;
}
// 压栈
int push_stack(top_st *t, data value)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
// 创建栈结点
linked_stack *lt = (linked_stack *)malloc(sizeof(linked_stack));
if (NULL == lt)
{
printf("创建栈结点失败\n");
return -1;
}
// 栈结点填充值
lt->value = value;
// 当前栈结点接入到之前栈结点的前面
lt->next = t->top;
// 栈顶指针指向当前栈结点
t->top = lt;
++t->len;
return 0;
}
// 弹栈
data pop_stack(top_st *t)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(t))
{
linked_stack *p = t->top;
data value = t->top->value;
t->top = t->top->next;
free(p);
--t->len;
return 0;
}
printf("此栈已空,不可再弹栈\n");
return -1;
}
// 遍历输出栈
int output(top_st *t)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
printf("当前栈内元素个数为 : %d\n", t->len);
linked_stack *p = t->top;
if (!is_empty(t))
{
int i = t->len;
printf("从栈顶到栈底元素依次为:\n");
for (int j = 0; i > 0 && NULL != p; i--, j++, p = p->next)
{
printf("第 %d 位为: %d\n", j + 1, p->value);
}
return 0;
}
printf("此栈已空,无元素可输出\n");
return -1;
}
// 栈清空
int clear_stack(top_st *t)
{
if (NULL == t)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(t))
{
linked_stack *p = t->top;
while (NULL != p)
{
t->top = p->next;
free(p);
--t->len;
p = t->top;
}
printf("此栈已清空\n");
return 0;
}
printf("此栈已空,不必再清空\n");
return -1;
}
// 销毁栈
int free_stack(top_st **t)
{
if (NULL == *t)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(*t))
{
linked_stack *p = (*t)->top;
while (NULL != p)
{
(*t)->top = p->next;
free(p);
--(*t)->len;
p = (*t)->top;
}
}
free(*t);
*t = NULL;
printf("此栈已销毁\n");
return 0;
}
测试用主函数(main.c)
#include "head.h"
int main(int argc, char const *argv[])
{
top_st *s = create_top();
printf("\n压栈\n");
push_stack(s, 12);
output(s);
printf("\n压栈\n");
push_stack(s, 21);
output(s);
printf("\n压栈\n");
push_stack(s, 32);
output(s);
printf("\n压栈\n");
push_stack(s, 23);
output(s);
printf("\n压栈\n");
push_stack(s, 13);
output(s);
printf("\n压栈\n");
push_stack(s, 31);
output(s);
printf("\n压栈\n");
push_stack(s, 33);
output(s);
printf("\n弹栈\n");
pop_stack(s);
output(s);
printf("\n弹栈\n");
pop_stack(s);
output(s);
printf("\n清空\n");
clear_stack(s);
output(s);
printf("\n弹栈\n");
pop_stack(s);
output(s);
printf("\n压栈\n");
push_stack(s, 99);
output(s);
puts("");
free_stack(&s);
printf("%p\n", s);
printf("\n弹栈\n");
pop_stack(s);
output(s);
printf("\n压栈\n");
push_stack(s, 99);
output(s);
return 0;
}
Makefile
EXE=linked_struct
CC=gcc
CFLAGs=-c
OBJs+=my_linked_struct.o
OBJs+=main.o
all:$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o linked_struct
五十五、 顺序循环队列
55.1 队列的概念
- 一端入,一端出的,操作受限的线性表
- 只允许一端入队,另一端出队。
- 先进先出(FIFO)First in first out
55.2 循环队列的结构体
#define MAX 6
typedef int data;
// 队列元素结点
typedef struct my_queue
{
data arr[MAX];
// 队头
int rear;
// 队尾
int front;
} my_queue;
55.3 循环队列的判空
头的位置与尾的位置相同
front == rear
55.4 循环队列的判满
头的下一个位置与尾的位置相同
(front+1)%MAX == rear
为了防止因队头不断增加导致溢出,故每次增加时都要对栈的最大值MAX取模,判满同理
55.5 入队(尾插)
// 入队(尾插)
int in_queue(my_queue *q, data value)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_full(q))
{
q->arr[q->rear] = value;
q->rear = (q->rear + 1) % MAX;
return 0;
}
printf("队列已满,无法入队\n");
return -1;
}
55.6 出队(头删)
// 出队(头删)
data out_queue(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(q))
{
data value= q->arr[q->front];
q->front = (q->front + 1) % MAX;
return value;
}
printf("队列为空,出队失败\n");
return -1;
}
55.7 遍历输出队列
// 遍历输出队列
int output(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(q))
{
int i=q->front;
for (int i=q->front; i != q->rear; i=(i+1)%MAX)
{
printf("%d\n",q->arr[i]);
}
return 0;
}
printf("队列为空,没有输出\n");
return -1;
}
55.8 队列清空
// 队列清空
int clear_queue(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
memset(q,0,sizeof(my_queue));
return 0;
}
55.9 销毁队列
// 销毁队列
int free_queue(my_queue **q)
{
if (NULL == *q)
{
printf("传入参数为空\n");
return -1;
}
free(*q);
*q=NULL;
return 0;
}
55.10 顺序循环队列的代码(接口,功能实现,测试用主函数,Makefile)
接口(head.h)
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 6
typedef int data;
// 队列元素结点
typedef struct my_queue
{
data arr[MAX];
// 队头
int rear;
// 队尾
int front;
} my_queue;
// 创建栈顶指针
my_queue *init();
// 队列的判空
int is_empty(my_queue *q);
// 队列的判满
int is_full(my_queue *q);
// 入队(头插)
int in_queue(my_queue *q, data value);
// 出队(尾删)
data out_queue(my_queue *q);
// 遍历输出队列
int output(my_queue *q);
// 队列清空
int clear_queue(my_queue *q);
// 销毁队列
int free_queue(my_queue **q);
#endif
功能实现(my_queue.c)
#include "head.h"
// 创建栈顶指针
my_queue *init()
{
my_queue *q = (my_queue *)malloc(sizeof(my_queue));
if (NULL == q)
{
printf("队列创建失败\n");
return NULL;
}
memset(q, 0, sizeof(my_queue));
return q;
}
// 队列的判空
int is_empty(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (q->front == q->rear)
{
printf("是个空队列\n");
return 1;
}
return 0;
}
// 队列的判满
int is_full(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (((q->rear) + 1) % MAX == q->front)
{
printf("是个满队列\n");
return 1;
}
}
// 入队(尾插)
int in_queue(my_queue *q, data value)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_full(q))
{
q->arr[q->rear] = value;
q->rear = (q->rear + 1) % MAX;
return 0;
}
printf("队列已满,无法入队\n");
return -1;
}
// 出队(头删)
data out_queue(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(q))
{
data value= q->arr[q->front];
q->front = (q->front + 1) % MAX;
return value;
}
printf("队列为空,出队失败\n");
return -1;
}
// 遍历输出队列
int output(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (!is_empty(q))
{
int i=q->front;
for (int i=q->front; i != q->rear; i=(i+1)%MAX)
{
printf("%d\n",q->arr[i]);
}
return 0;
}
printf("队列为空,没有输出\n");
return -1;
}
// 队列清空
int clear_queue(my_queue *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
memset(q,0,sizeof(my_queue));
return 0;
}
// 销毁队列
int free_queue(my_queue **q)
{
if (NULL == *q)
{
printf("传入参数为空\n");
return -1;
}
free(*q);
*q=NULL;
return 0;
}
测试用主函数(main.c)
#include "head.h"
int main(int argc, char const *argv[])
{
my_queue *q = init();
printf("\n入队\n");
in_queue(q, 12);
output(q);
printf("\n入队\n");
in_queue(q, 21);
output(q);
printf("\n入队\n");
in_queue(q, 32);
output(q);
printf("\n入队\n");
in_queue(q, 23);
output(q);
printf("\n入队\n");
in_queue(q, 13);
output(q);
printf("\n入队\n");
in_queue(q, 31);
output(q);
printf("\n入队\n");
in_queue(q, 33);
output(q);
printf("\n出队\n");
out_queue(q);
output(q);
printf("\n出队\n");
out_queue(q);
output(q);
printf("\n清空\n");
clear_queue(q);
output(q);
printf("\n出队\n");
out_queue(q);
output(q);
printf("\n入队\n");
in_queue(q, 99);
output(q);
puts("");
free_queue(&q);
printf("%p\n", q);
printf("\n出队\n");
out_queue(q);
output(q);
printf("\n入队\n");
in_queue(q, 99);
output(q);
return 0;
}
Makefile
EXE=my_queue
CC=gcc
CFLAGs=-c
OBJs+=my_queue.o
OBJs+=main.o
all:$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o my_queue.c
五十六、 链式队列
56.1 链式队列的结构体
链队元素结点:
// 链队元素结点中值的类型的别名
typedef int data;
// 链队元素结点
typedef struct linked_queue
{
// 链队的值
data value;
// 链队的next指针域
struct linked_queue *next;
} linked_queue; // 链队结点类型的的别名
链队指针,用于指向队头和队尾:
// 链队指针,用于指向队头和队尾
typedef struct queue_point
{
// 链队中元素个数
int len;
// 队头
linked_queue *front;
// 队尾
linked_queue *rear;
} queue_point; // 链队指针类型的别名
56.2 创建链队指针
// 创建链队指针
queue_point *create_point()
{
// 创建链队指针
queue_point *q = (queue_point *)malloc(sizeof(queue_point));
// 没创建成功,提示创建失败,并返回NULL
if (NULL == q)
{
printf("创建队列指针失败\n");
return NULL;
}
// 链队指针创建成功,将链队元素结点个数初始化为0
// 链队的队头指针和队尾指针都指向NULL
q->len = 0;
q->rear = NULL;
q->front = NULL;
// 返回创建的链队指针地址
return q;
}
56.3 链队入队(尾插)
// 链队入队(尾插----链表的尾部,不是队列的尾,是队列的头)
int in_queue(queue_point *q, data value)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 创建链队元素结点
linked_queue *lq = (linked_queue *)malloc(sizeof(linked_queue));
// 创建失败,结束程序,返回-1表示函数异常结束
if (NULL == q)
{
printf("创建队列结点失败\n");
return -1;
}
// 创建链队元素结点成功,将链队元素结点填充值,并将next指针域置空
lq->value = value;
lq->next = NULL;
// 如果链队是空的,那么队头要指向这个结点
// 第一个结点,队头队尾都是它
if (is_empty(q))
{
q->front = lq;
// q->rear = lq; // 可以现在先不指向,因为后面都会指向
}
// 如果链队不是空的,那么链队就存在队头和队尾
// 所以只需要更新队尾
// 先让新建的结点跟在旧的队尾后面
else
{
q->rear->next = lq;
}
// 让队尾指向新建的这个结点
q->rear=lq;
// 链队的元素个数+1
++q->len;
return 0;
}
56.4 链队出队(头删)
// 链队出队(头删----链表的头部,不是队列的头,是队列的尾)
data out_queue(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 链队为空时提示并退出
if (is_empty(q))
{
printf("链队为空,无元素出队\n");
return -1;
}
// 链队非空时
// 搞个链队结点,用于指向队头出队的结点
// (类比银行排队时队头处理完的那个人会离开队伍)
linked_queue *lq = q->front;
// 之前的队头准备走了,让旧队头的下一个成为新队头
q->front = lq->next;
// 暂存队头的数据
data t = lq->value;
// 释放旧队头
free(lq);
// 队列元素个数-1
--q->len;
return t;
}
56.5 遍历输出队列
// 遍历输出队列
int output(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (is_empty(q))
{
printf("队列为空,无元素可输出\n");
return -1;
}
// 队列不为空时
// 声明一个结点用于指向要输出的结点,首先从队头开始
linked_queue *lq = q->front;
printf("队列中当前元素个数为:%d\n", q->len);
// 如果指到了队尾的next指针域,则进行退出
while (NULL != lq)
{
printf("%d\n", lq->value);
// 当前要输出的结点向后挪
lq = lq->next;
}
return 0;
}
56.6 队列清空、销毁队列
// 队列清空
int clear_queue(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 用于指向待清空的结点,从队头开始
linked_queue *lq = q->front;
// 如果待清空的结点为NULL
// 要么本就是空的队,队头是空的
// 要么是指到了队尾的next指针域
while (NULL != lq)
{
// 先让新的队头变成旧队头的下一个,即原来的第二个
q->front = lq->next;
// 将旧队头释放
free(lq);
// 队列结点个数-1
--q->len;
// 将新的队头变成准备删除的结点,最多让新队头变成队尾的next指针域
lq = q->front;
}
// 循环结束之后,此时待删除结点指向了队尾的next指针域,即NULL
// 所以让队头再次指向NULL,貌似这句有点多余
q->front = lq;
return 0;
}
// 销毁队列
int free_queue(queue_point **q)
{
if (NULL == *q)
{
printf("传入参数为空\n");
return -1;
}
// 清理掉链队后,需要将链队指针的空间也释放
clear_queue(*q);
free(*q);
// 让链队指针指向NULL
*q = NULL;
return 0;
}
56.7 链式队列的代码(接口,功能实现,测试用主函数,Makefile)
接口(head.h)
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 链队元素结点中值的类型的别名
typedef int data;
// 链队元素结点
typedef struct linked_queue
{
// 链队的值
data value;
// 链队的next指针域
struct linked_queue *next;
} linked_queue; // 链队结点类型的的别名
// 链队指针,用于指向队头和队尾
typedef struct queue_point
{
// 链队中元素个数
int len;
// 队头
linked_queue *front;
// 队尾
linked_queue *rear;
} queue_point; // 链队指针类型的别名
// 创建链队指针
queue_point *create_point();
// 链队判空
int is_empty(queue_point *q);
// 链队入队(尾插----链表的尾部,不是队列的尾,是队列的头)
int in_queue(queue_point *q, data value);
// 链队出队(头删----链表的头部,不是队列的头,是队列的尾)
data out_queue(queue_point *q);
// 遍历输出链队
int output(queue_point *q);
// 链队清空
int clear_queue(queue_point *q);
// 销毁链队
int free_queue(queue_point **q);
#endif
功能实现(linked_queue.c)
#include "head.h"
// 创建链队指针
queue_point *create_point()
{
// 创建链队指针
queue_point *q = (queue_point *)malloc(sizeof(queue_point));
// 没创建成功,提示创建失败,并返回NULL
if (NULL == q)
{
printf("创建队列指针失败\n");
return NULL;
}
// 链队指针创建成功,将链队元素结点个数初始化为0
// 链队的队头指针和队尾指针都指向NULL
q->len = 0;
q->rear = NULL;
q->front = NULL;
// 返回创建的链队指针地址
return q;
}
// 链队判空
int is_empty(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 链队指针的队头或者队尾指向NULL时链队为空
if (NULL == q->front || NULL == q->rear)
{
return 1;
}
return 0;
}
// 链队入队(尾插----链表的尾部,不是队列的尾,是队列的头)
int in_queue(queue_point *q, data value)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 创建链队元素结点
linked_queue *lq = (linked_queue *)malloc(sizeof(linked_queue));
// 创建失败,结束程序,返回-1表示函数异常结束
if (NULL == q)
{
printf("创建队列结点失败\n");
return -1;
}
// 创建链队元素结点成功,将链队元素结点填充值,并将next指针域置空
lq->value = value;
lq->next = NULL;
// 如果链队是空的,那么队头要指向这个结点
// 第一个结点,队头队尾都是它
if (is_empty(q))
{
q->front = lq;
q->rear = lq;
}
// 如果链队不是空的,那么链队就存在队头和队尾
// 所以只需要更新队尾
// 先让新建的结点跟在旧的队尾后面
else
{
q->rear->next = lq;
}
// 让队尾指向新建的这个结点
q->rear=lq;
// 链队的元素个数+1
++q->len;
return 0;
}
// 链队出队(头删----链表的头部,不是队列的头,是队列的尾)
data out_queue(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 链队为空时提示并退出
if (is_empty(q))
{
printf("链队为空,无元素出队\n");
return -1;
}
// 链队非空时
// 搞个链队结点,用于指向队头出队的结点
// (类比银行排队时队头处理完的那个人会离开队伍)
linked_queue *lq = q->front;
// 之前的队头准备走了,让旧队头的下一个成为新队头
q->front = lq->next;
// 暂存队头的数据
data t = lq->value;
// 释放旧队头
free(lq);
// 队列元素个数-1
--q->len;
return t;
}
// 遍历输出队列
int output(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
if (is_empty(q))
{
printf("队列为空,无元素可输出\n");
return -1;
}
// 队列不为空时
// 声明一个结点用于指向要输出的结点,首先从队头开始
linked_queue *lq = q->front;
printf("队列中当前元素个数为:%d\n", q->len);
// 如果指到了队尾的next指针域,则进行退出
while (NULL != lq)
{
printf("%d\n", lq->value);
// 当前要输出的结点向后挪
lq = lq->next;
}
return 0;
}
// 队列清空
int clear_queue(queue_point *q)
{
if (NULL == q)
{
printf("传入参数为空\n");
return -1;
}
// 用于指向待清空的结点,从队头开始
linked_queue *lq = q->front;
// 如果待清空的结点为NULL
// 要么本就是空的队,队头是空的
// 要么是指到了队尾的next指针域
while (NULL != lq)
{
// 先让新的队头变成旧队头的下一个,即原来的第二个
q->front = lq->next;
// 将旧队头释放
free(lq);
// 队列结点个数-1
--q->len;
// 将新的队头变成准备删除的结点,最多让新队头变成队尾的next指针域
lq = q->front;
}
// 循环结束之后,此时待删除结点指向了队尾的next指针域,即NULL
// 所以让队头再次指向NULL,貌似这句有点多余
q->front = lq;
return 0;
}
// 销毁队列
int free_queue(queue_point **q)
{
if (NULL == *q)
{
printf("传入参数为空\n");
return -1;
}
// 清理掉链队后,需要将链队指针的空间也释放
clear_queue(*q);
free(*q);
// 让链队指针指向NULL
*q = NULL;
return 0;
}
测试用主函数(main.c)
#include "head.h"
int main(int argc, char const *argv[])
{
queue_point *s = create_point();
printf("\n入队\n");
in_queue(s, 12);
output(s);
printf("\n入队\n");
in_queue(s, 21);
output(s);
printf("\n入队\n");
in_queue(s, 31);
output(s);
printf("\n入队\n");
in_queue(s, 33);
output(s);
printf("\n出队\n");
out_queue(s);
output(s);
printf("\n出队\n");
out_queue(s);
output(s);
printf("\n清空\n");
clear_queue(s);
output(s);
printf("\n出队\n");
out_queue(s);
output(s);
printf("\n入队\n");
in_queue(s, 99);
output(s);
puts("");
free_queue(&s);
printf("%p\n", s);
printf("\n出队\n");
out_queue(s);
output(s);
printf("\n入队\n");
in_queue(s, 99);
output(s);
return 0;
}
Makefile
EXE=linked_queue
CC=gcc
CFLAGs=-c
OBJs+=linked_queue.o
OBJs+=main.o
all:$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o linked_queue
小作业
使用递归实现程序:输入一个数,输出该数的每一位
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int output(int num);
int main(int argc, const char *argv[])
{
int num;
printf("请输入一个数:");
scanf("%d", &num);
output(num);
return 0;
}
int output(int num)
{
if (num < 1)
{
return num;
}
else
{
printf("%d\n", num % 10);
return output(num/10);
}
}