单链表实现:单链表的实现_i跑跑的博客-CSDN博客
目录
一、队列的概念
只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
的特点。入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
二、队列的实现
分析:
队列要进行的是尾插,头删,因此用列表更优,我们用单链表来实现队列的核心功能
定义
定义单结点,有元素,和下一个结点的地址。
要对头和尾进行操作,那么在定义两个指针来指向链表首尾
队列是一个结构体,将首位两指针放入队列表示队列的首尾
typedef int QDatatype;
//定义单链表结点
typedef struct QueueNode
{
QDatatype data;
struct QueueNode* next;
}QNode;
//定义队列
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
初始化和销毁
初始化
队列初始化首尾为空
//队列初始化 void QueueInit(Queue* pq) { assert(pq); pq->head = pq->tail = NULL; }
销毁
注意:不能直接将队列首尾指针置空,若队列本身不为空,首尾指针置空会造成野指针问题。
先将队列中每个结点释放后,再对队列的首尾进行置空。
//队列销毁
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;
}
入队,对尾操作
相当于单链表尾插
断言后先进行结点的开辟。因为没有创建哨兵结点,所以我们要判断头为空时的情况。
尾插后记得更新尾结点。
//入队
void QueuePush(Queue* pq, QDatatype x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
assert(newnode);
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;
}
}
出队 ,对头操作
断言时还要判断队列是否为空,即assert(pq->head&&pq->tail);
这里要注意为什么判断的时head的next是否为空而不是直接判断head:
若队列只有一个结点时,此时head=tail,head指向next,head置空,但此时tail还指向原head的位置,会造成野指针的问题。
//出队
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head&&pq->tail);
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;
}
}
判断是否为空
当head和tail为空时返回true,否则返回false,直接return即可
//判断是否为空 bool QueueEmpty(Queue* pq) { assert(pq); return pq->head == NULL&&pq->tail == NULL; }
队列元素个数
直接计数遍历返回即可,但是这样效率会降低。
优化:直接在定义队列时,在首尾指针下加入一个计数变量,初始化时置0,每次入队时++,出队时--,需要用到个数时直接返回即可。
//队列元素个数
size_t QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
队头元素和队尾元素
通过首尾指针直接访问结点元素即可。
//对头元素
QDatatype QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
//队尾元素
QDatatype QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
test.c测试
直接手动创建队列进行入队出队测试:
入队:1 2 3 4 5
出队预计:1 2 3 4 5
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q,1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
while (!QueueEmpty(&q))
{
printf("%d ",QueueFront(&q));
QueuePop(&q);
}
printf("\n");
}
栈和队列运行对比
1 2 3 4 5
栈: 后进先出 5 4 3 2 1
队列:先进先出 1 2 3 4 5