【数据结构初阶】一文详解顺序栈和链队列的基本操作(下)

简介: 【数据结构初阶】一文详解顺序栈和链队列的基本操作

1.队列的概念

队列是一种特殊的线性表,特殊在只能从一端进行插入操作,另一端进行删除操作,队列具有Fist  In First Out的原则。

队尾:进行插入操作的一端,这个过程叫做入队列

队头:进行删除操作的一端,这个过程叫做出队列

c54e7264defb43918b2342290bd9bdac.png

抽号机:先来先服务,先给号码排队 (涉及嵌入式)


8dc1471c4f6c4ed1b1faea9dae2decde.png

2.队列的结构

队列我们采用链表实现:顺序表在满了要扩容,删完了后再入队列的时候还得扩容

链表的话,入队列就是尾插,定义一个尾指针。出队列就是头删,定义一个头指针

3.实现队列的基本操作

3-1结构体定义

b3af918729e74116b32dd1fc3531babc.png

typedef int QDateType;
typedef struct QueueNode
{
  struct QueueNode* next;
  QDateType val;
}QueueNode;
typedef struct Queue
{
  QueueNode* head;
  QueueNode* tail;
}Queue;

3-2队列的初始化

这里的链表队列我并没有带头,没有带头就要在入队列和出队列时有一点特殊情况的考虑

void QueueInit(Queue* ps)
{
  assert(ps);
  ps->head = ps->tail = NULL;
}

3-3入队列

相当于尾插,考虑特殊情况:队列为空的情况

//入队列:尾插
void QueuePush(Queue* ps,QDateType x)
{
  assert(ps);
  QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
  newnode->next = NULL;
  newnode->val = x;
  if (newnode == NULL)
  {
    perror("malloc fail.");
    exit(-1);
  }
  if (ps->tail == NULL)
  {
    ps->head = ps->tail = newnode;
  }
  else
  {
    ps->tail->next = newnode;
    ps->tail = ps->tail->next;
  }
}

3-4出队列

相当于头删,考虑特殊情况:只有一个结点的情况,出队列后要改变ps->tail

void QueuePop(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  if (ps->head->next == NULL)
  {
    free(ps->head);
    ps->head = ps->tail = NULL;
  }
  else
  {
    QueueNode* next = ps->head->next;
    free(ps->head);
    ps->head = next;
  } 
}

3-5取队头元素

QDateType QueueFront(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->head->val;
}

3-6取队尾元素

QDateType QueueBack(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->tail->val;
}

3-7队列判空

1. bool QueueEmpty(Queue* ps)
2. {
3.  assert(ps);
4.  return ps->tail == NULL;
5. }

3-8队列长度

int QueueSize(Queue* ps)
{
  assert(ps);
  int size = 0;
  QueueNode* cur = ps->head;
  while(cur)
  {
    ++size;
    cur = cur->next;
  }
  return size;
}

3-9队列销毁

void QueueDestory(Queue* ps)
{
  assert(ps);
  QueueNode* cur = ps->head;
  while (cur)
  {
    QueueNode* next = cur->next;
    free(cur);
    cur = next;
  }
  ps->head = ps->tail = NULL;
}

4.源代码

4-1queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"
void QueueInit(Queue* ps)
{
  assert(ps);
  ps->head = ps->tail = NULL;
}
void QueueDestory(Queue* ps)
{
  assert(ps);
  QueueNode* cur = ps->head;
  while (cur)
  {
    QueueNode* next = cur->next;
    free(cur);
    cur = next;
  }
  ps->head = ps->tail = NULL;
}
//入队列:尾插
void QueuePush(Queue* ps,QDateType x)
{
  assert(ps);
  QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
  newnode->next = NULL;
  newnode->val = x;
  if (newnode == NULL)
  {
    perror("malloc fail.");
    exit(-1);
  }
  if (ps->tail == NULL)
  {
    ps->head = ps->tail = newnode;
  }
  else
  {
    ps->tail->next = newnode;
    ps->tail = ps->tail->next;
  }
}
void QueuePop(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  if (ps->head == ps->tail)
  {
    free(ps->head);
    ps->head = ps->tail = NULL;
  }
  else
  {
    QueueNode* next = ps->head->next;
    free(ps->head);
    ps->head = next;
  } 
}
QDateType QueueFront(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->head->val;
}
QDateType QueueBack(Queue* ps)
{
  assert(ps);
  assert(!QueueEmpty(ps));
  return ps->tail->val;
}
bool QueueEmpty(Queue* ps)
{
  assert(ps);
  return ps->tail == NULL;
}
int QueueSize(Queue* ps)
{
  assert(ps);
  int size = 0;
  QueueNode* cur = ps->head;
  while(cur)
  {
    ++size;
    cur = cur->next;
  }
  return size;
}

4.2queue.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int QDateType;
typedef struct QueueNode
{
  struct QueueNode* next;
  QDateType val;
}QueueNode;
typedef struct Queue
{
  QueueNode* head;
  QueueNode* tail;
}Queue;
void QueueInit(Queue* ps);
void QueuePush(Queue* ps, QDateType x);
void QueuePop(Queue* ps);
QDateType QueueFront(Queue* ps);
QDateType QueueBack(Queue* ps);
bool QueueEmpty(Queue* ps);
int QueueSize(Queue* ps);
void QueueDestory(Queue* ps);

4.3test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"
int main()
{
  Queue Q;
  QueueInit(&Q);
  QueuePush(&Q, 1);
  QueuePush(&Q, 2);
  QueuePush(&Q, 3);
  QueuePush(&Q, 4);
  QueuePush(&Q, 5);
  QDateType ret1 = QueueFront(&Q);
  printf("QueueFront:%d\n", ret1);
  QDateType ret2 = QueueBack(&Q);
  printf("QueueBack:%d\n", ret2);
  int size = QueueSize(&Q);
  printf("size:%d\n", size);
  while (!QueueEmpty(&Q))
  {
    printf("%d", QueueFront(&Q));
    QueuePop(&Q);
  }
  QueueDestory(&Q);
  return 0;
}

4.4效果图


025e2f7d9fc7441d97ba59b4fe9111fd.png


目录
相关文章
|
20天前
|
算法 C语言
【数据结构与算法 经典例题】使用栈实现队列(图文详解)
【数据结构与算法 经典例题】使用栈实现队列(图文详解)
|
14天前
|
存储 缓存 算法
堆和栈的区别及应用场景
堆和栈的区别及应用场景
|
20天前
|
存储 测试技术
【数据结构】操作受限的线性表,栈的具体实现
【数据结构】操作受限的线性表,栈的具体实现
27 5
|
20天前
|
算法 C语言
【数据结构与算法 经典例题】使用队列实现栈(图文详解)
【数据结构与算法 经典例题】使用队列实现栈(图文详解)
|
21天前
|
算法
【C/数据结构和算法】:栈和队列
【C/数据结构和算法】:栈和队列
23 1
|
25天前
|
C++
【洛谷 P1044】[NOIP2003 普及组] 栈 题解(递归+记忆化搜索)
**NOIP2003普及组栈问题**:给定操作数序列1到n,仅允许push(进栈)和pop(出栈)操作。目标是计算所有可能的输出序列总数。输入包含一个整数n(1≤n≤18)。示例输入3,输出5。当队列空时返回1,栈空则只能入栈,栈非空时可入栈或出栈。AC C++代码利用记忆化搜索求解。
17 1
|
9天前
|
API
用栈翻转字符串
用栈翻转字符串
14 0
|
9天前
|
JavaScript
数据结构(用 JS 实现栈和队列【三种方式】)
数据结构(用 JS 实现栈和队列【三种方式】)
16 0
|
13天前
|
存储 缓存 算法
堆和栈的区别及应用场景
堆和栈的区别及应用场景
|
14天前
|
算法
数据结构与算法:栈与队列
数据结构与算法:栈与队列