队列的实现-C语言


注:本文系岭南师范学院物联网俱乐部原创部分训练计划,转载请保留声明。

前言

前面跟大家讨论了堆栈的几种办法,如静态数组堆栈、动态数组堆栈和链表堆栈,今天主要跟大家讲一下队列的实现,队列是一种“先进先出的数据结构”,可分为静态队列和链式队列。链式队列则是通过尾插法实现,静态队列一般使用数组实现,数组需要预先定义内存大小,为了避免内存浪费,一般使用循环队列。

一、链式队列

/*
引用头文件""和<>的区别
#include" "引用的是你程序目录的相对路径中的头文件。
#include< >引用的是编译器的类库路径里面的头文件。

stdio .h 头文件定义了三个变量类型、一些宏和各种函数来执行输入和输出。
C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息。
C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

思路: 头插法和尾插法顾名思义,就是在链表加入新结点的时候是在头部插入还是在尾部插入。
 尾插法不改变链表的原本顺序,在遍历链表的时候,正好就对应了队列的先进先出的特性;
头插法会改变链表原本的顺序,在遍历链表的时候也是正好对应了栈的先进后出的特性。

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/***********定义一个结构体类型,在文本段***************/
typedef struct queue
{
 int value;            //数据域
 struct queue *next;   //指针域
}queue_t;


queue_t *head; //定义头指针,在栈区
queue_t *tail; //定义尾指针,在栈区
queue_t *prt;  //定义指针变量prt用于遍历,在栈区

/******定义一个判断头结点为空的函数,在文本段********/
unsigned int empty()
{
  return head == NULL; //如果头结点为空,返回1
}

/******定义一个增加队列函数,在文本段********/
void add_queue()
{
  queue_t *new_node;	                            //建立一个指针变量
  for(int num=0;num<8;num++)                      //用一个for循环来循环创建新的结点
  { 
  new_node = (queue_t*)malloc(sizeof(queue_t));   //malloc申请一块内存给新节点并存在指针中,new_node指向这个内存的首地
  memset(new_node,0,sizeof(*new_node));//memset是设置new_node指向的这个首地址开始到首地址+sizeof(*new_node)这个长度元素为0
  new_node->next=NULL;                 //内存(结构体)的指针域为0
  new_node->value=num+1;               //内存(结构体)数据域增加数据
  if(head == NULL )                    //若头指针为空,则是第一个结点,new_node存的地址给head,head指向首个节点
  {
   head=new_node;
  }
  else                                  //若头指针不为空,new_node存的地址给tail指向现在的这个节点的指针域(如第二个节点),这个时候第二个节点将会连接第三个节点
  {
   tail->next=new_node;
  }
   tail=new_node;                       //ew_node存的地址给tail,这个时候tail也会连接下一个节点(如:第三个节点)
  }
}

/******定义一个删除队列函数,在文本段********/
void delete_queue()
{
 queue_t *first_node;       //定义一个新的指针变量
 first_node = head;         //head指针的值给了first_node,first将会指向head本来连接的节点(如第二个节点)
 head = first_node->next;   //first_node能获取已经连接的节点的指针域(如第二个节点),这个指针域存在了连接下一个节点的地址(如第三节点),赋值给head,head将会指向这个节点
 free(first_node);          //释放掉first_node,即清除第二个节点的内存
 if(head == NULL)           //主要考虑到特殊情况,如剩下最后一个节点时,想将它清掉,需要头指针指向为0,尾指针也为0
 {
  tail==NULL;
 }
}

/******定义一个销毁队列函数,在文本段********/
void destroy_queue()         //判断队列是否为空,可一个一个一个破坏       
{
 if(!empty())
 {
  delete_queue();
 }
}

int main()
{
 printf("创建队列:");
 add_queue();
 for(prt=head;prt!=NULL;prt=prt->next)  //循环实现遍历,意思为每循环一次,prt指向新的节点
 {
  printf("%d\n",prt->value);            //prt指向新的节点后,便能拿到里面的value值(数据域)
 }
  printf("\n\n");

  printf("删除队列");

  for(int i=0;i<4;i++)
 {
  delete_queue();
 }
  for(prt=head;prt!=NULL;prt=prt->next)
 {
  printf("%d\n",prt->value);
 }
  printf("\n\n");

}

二、循环队列

/*
引用头文件""和<>的区别
#include" "引用的是你程序目录的相对路径中的头文件。
#include< >引用的是编译器的类库路径里面的头文件。

stdio .h 头文件定义了三个变量类型、一些宏和各种函数来执行输入和输出。
C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息。
C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

思路:队列是一种“先进先出的数据结构”,可分为静态队列和链式队列。
静态队列一般使用数组实现,数组需要预先定义内存大小,为了避免内存浪费,一般使用循环队列。接下来讲述循环队列的原理以及实现代码。
->:在用结构体指针的时候才能用,常用与指针变量指向结构体成员的值

提示:front和rear不会超过max——queue_num,并且作为data数组的下标
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define max_queue_num 10 //循环队列的最大长度

typedef struct cir_queue //定义一个cir_queue结构体
{
 int front;              //指向队列头,指向第一个数据节点
 int rear;               //指向队尾列(并不是指向最后一个数据节点,而是最后一个数据节点的位置)
 char data[max_queue_num];//节点数据,根据实际需要可以是不同的数据类型,但因为是数组,需要在声明时候指定大小。
}queue_t;

void queue_init(queue_t *queue)//初始化data的数组的数据,front和rear设为0
{
 queue->front=0;
 queue->rear=0;
 /*
 memset()函数,意思:queue->data这个是指针或者数组的地址,填充(替换)max_queue_num长度的地址里面的内容变为0
 在memset()函数里,queue->data是一个地址
但是像new_node->value=value这样子,new_node->value是value这个地址里面的址。
 */memset(queue->data,0,max_queue_num);
}

int empty(queue_t *queue )//
{
  return (queue->front == queue->rear);//头指针等于尾指针就为空
}

int full(queue_t *queue)
{
  return(((queue->rear+1)%max_queue_num == queue->front));//当real等于9的时候,加上1等于10除10,余数为0,与front相等,所以满了,但其实这个时候real只是等9
}

void destroy_queue(queue_t *queue)
{
  if(queue == NULL)
  {
    printf("队列不存在");
  }
  else
  {
   free(queue);
  }
}

void add_queue(queue_t *queue , char newdata)
{
 if(full(queue))
 {
  printf("队列已满!");
  return ;
 }
 queue->data[queue->rear]=newdata;//这里的rear不会到9,因为一当9,就是打印队列已经满了
 queue->rear=(queue->rear+1)%max_queue_num;//用(queue->rear+1)%max_queue_num为了防止队列已经满的状态下,删光,重新加,这样子rear超过max_queue_num
}

void delete_queue(queue_t *queue)
{
 if(empty(queue))
 {
   printf("队列为空!");
   return ;
 }
  queue->front=(queue->front+1)%max_queue_num;//从头开始删除
}

void queue_print(queue_t *queue)
{
 for(int num=queue->front;num!=queue->rear;num=(num+1)%max_queue_num)
 {
  printf("%c\n",queue->data[num]);  //从头开始打印
 }
}

int main()
{
  queue_t *que=(queue_t*)malloc(sizeof(queue_t));
  if(!que)
  {
   printf("malloc分配失败!");
  }
  queue_init(que);
  printf("新建队列");
  add_queue(que,'a');
  add_queue(que,'b');
  add_queue(que,'c');
  queue_print(que);
  printf("\n");
 
  printf("删除队列");
  delete_queue(que);
  queue_print(que);

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小贤风帆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值