c++ 队列_Linux_C开发_第八天_数据结构_队列

本文主要内容:顺序循环队列,链式队列,栈实现队列

队列:队列和栈一样只允许在断点处插入和删除元素。先进先出(FIFO)

作用:缓冲,排队,等待

 117a4b6607424e4cf3454d590fe94728.png

顺序循环队列

初始状态:一个头一个尾,头出尾进,出队对头操作,入队对尾操作。

512e06fb2439d2fd77366e35e66c8e92.png

注意点:

  1.  在栈中和表中,top和last都是表示数据存在的位置,而在队列中,head和tail有时有有时没有。

    head和tail表示“即将”,head表示即将在head位置出队,tail表示即将在tail位置出队。

  2. head++,tail++,到了尾部应该怎么办?

    h = (h+1)% s

    t = (t+1)% s

  3. 为什么最多放S-1个?

    t == h 放着放着就满了,但是存在两义性,和空队列一样。所以只放S-1个,t和h不重叠。

  4. 什么时候是空,什么时候是满?

    队列最多只能放S-1个

    (t+1)%s == h     t再放一个就满了

    或(t-h+s)%s == s-1   (长度公式)

b12d3a9f23dc659fbdb4cb10eebd385e.png

第一种:此时 t-h == 4;   t+1 == 5;   可得  t-h+s == 9;

257fbb784b884b97c4ec0df235c4967c.png

    第二种:此时 t-h == -1;  t+1 == h;    可得  t-h+s == 5;

为了同时满足第一种和第二种 可得下面公式: !!重点!!

(t+1)%s == h

(t-h+s)% s == s-1    

定义结构体:

typedef struct node {  int * data;//存数据元素  int size;//标记数据元素个数  int head;//即将要取数据的位置(下标)  int tail;//即将要存数据的位置(下标)}queue_t;//顺序循环队列的数据类型

创建:

queue_t* create_queue(int size){  if(size<=0||size>20000)    return NULL;  //申请顺序循环队列标识的空间  queue_t* queue=malloc(sizeof(queue_t));  if(queue == NULL) {    printf("标识申请空间失败!\n");    return NULL;  }  //申请存储数据元素空间  queue->data=malloc(sizeof(int)*size);  if(queue->data == NULL) {    printf("数据空间申请失败!\n");    return NULL;  }  //标记数据元素个数  queue->size=size;  //初始状态约定head和tail都保存0位置  queue->head=queue->tail=0;  return queue;}

判空判满:

//判满int isfull_queue(queue_t * queue) {  return queue->head == (queue->tail + 1) % queue->size;}//判空int isnull_queue(queue_t * queue) {  return queue->head == queue->tail;}//判满2 s大小的队列 最多存放 s-1个元素  (不让h和t在放满的情况下重合)int isfull_queue_length(queue_t* queue){  return (queue->tail-queue->head+queue->size)%queue->size==queue->size-1;}

入队:

int push_queue(queue_t* queue,int data) {  if(queue==NULL||isfull_queue(queue))    return -1;  queue->data[queue->tail]=data;  //修改tail的值(假使tail在7位置,存入数据后指向下一个位置0,所以操作时需要对队列长度取余)  queue->tail=(queue->tail+1)%queue->size;  return 0;}

出队:

int pop_queue(queue_t* queue,int *data) {  //0   容错  if(queue==NULL||isnull_queue(queue))    return -1;  //1   取数据  *data=queue->data[queue->head];  queue->data[queue->head]=0;  //2   head 变化  queue->head=(queue->head+1)%queue->size;  return 0;}

假打印(0~N~1):

int printf_fromzero_fake(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  int i;  for(i=0;isize;i++)  {    printf("%3d ",queue->data[i]);  }  printf("\n");  return 0;}

假打印 h~t:

int printf_from_h_to_t_fake(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  int i;  for(i=queue->head;i!=queue->tail;i=(i+1)%queue->size)  {    printf("%3d ",queue->data[i]);  }#if 0  i=queue->head;  while(i!=queue->tail)  {    printf("%3d ",queue->data[i]);    i=(i+1)%queue->size;  }#endif  printf("\n");  return 0;}

真打印  (再造一个队列):

int printf_queue_real(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  queue_t* temp=create_queue(queue->size);  // queue_t* temp=create_queue(length_queue(queue)+1);  int data;  while(!isnull_queue(queue)) {    pop_queue(queue,&data);    printf("%3d ",data);    push_queue(temp,data);  }  while(!isnull_queue(temp)) {    pop_queue(temp,&data);    push_queue(queue,data);  }  destroy_queue(&temp);  printf("\n");  return 0;}

真逆打印 (造两个栈 实现一个队列):

9a3d59135ba632e19731d478d10b7c2f.png

int reprintf_queue_real(queue_t* queue){  if(queue==NULL||isnull_queue(queue))    return -1;  int *s1=malloc(sizeof(int)*length_queue(queue));  int *s2=malloc(sizeof(int)*length_queue(queue));  int top1=-1;  int top2=-1;  int data;  while(!isnull_queue(queue)) {    pop_queue(queue,&data); //出队    s1[++top1]=data; //入栈  第1步  }  while(top1!=-1) {    data=s1[top1--]; //出栈,此时已倒序   第2步    printf("%3d ",data);    s2[++top2]=data; //入第二个栈     }  while(top2!=-1) {    data=s2[top2--];//出栈,顺序再次逆,变为正  第3步    push_queue(queue,data); //入队  }  printf("\n");  //销毁  free(s1);  free(s2);  return 0;}

长度:

int length_queue(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return 0;  return (queue->tail-queue->head+queue->size)%queue->size;}

清空:

int clear_queue(queue_t* queue) {  if(queue==NULL)    return -1;  queue->head=queue->tail=0;  return 0;}

销毁:

int destroy_queue(queue_t** queue) {  if(*queue==NULL)    return -1;  free((*queue)->data);  free(*queue);  *queue=NULL;  return 0;}

main函数:

#include #include typedef struct node {  int * data;//存数据元素  int size;//标记数据元素个数  int head;//即将要取数据的位置(下标)  int tail;//即将要存数据的位置(下标)}queue_t;//顺序循环队列的数据类型int main(int argc, const char *argv[]){  queue_t* queue=create_queue(30);  int i;  for(i=1;i<=20;i++) {    push_queue(queue,i);    //printf_fromzero_fake(queue);    printf_from_h_to_t_fake(queue);  }  printf("length_queue:%d\n",length_queue(queue));#if 0  int data;  for(i=1;i<=20;i++) {    pop_queue(queue,&data);    printf("pop data:%d\n",data);    //printf_fromzero_fake(queue);    printf_from_h_to_t_fake(queue);  }#endif  printf("real printf:");  printf_queue_real(queue);  printf("reprintf_queue_real:\n");  reprintf_queue_real(queue);  clear_queue(queue);  printf("length_queue:%d\n",length_queue(queue));  destroy_queue(&queue);  if(queue==NULL) {    printf("success destroyed\n");  }  return 0;}

链式队列

链式队列,首先是链表,加上两个指向头和尾的指针!

采用尾进头出:

原因:头部插删都方便,而尾部插方便,删不方便!

fd478ecc06c2b5658ad329287bc8f079.png

定义结构体(一个链表和一个头尾):

typedef struct node1 {  int data;//数据域  struct node1 * next;//指针域}list_t;//结点的数据类型typedef struct node2 {  list_t* head;//头指针,指向链式队列的头  list_t* tail;//尾指针,指向链式队列的尾巴}queue_t;//链式队列的数据类型

创建:头尾都指向第一个空节点。

bab27df258dc9a715781d91f40b3f19e.png

queue_t* create_queue(void) {  //申请队列标识即申请头指针和尾指针的存储空间  queue_t* queue=malloc(sizeof(queue_t));  if(queue== NULL) {    printf("队列标识申请失败!\n");    return NULL;  }    //申请头结点的空间  queue->head=malloc(sizeof(list_t));  if(head == NULL) {    printf("头结点申请失败!\n");    return NULL;  }  //头结点初始化  queue->head->next=NULL;  //初始化头指针和尾指针,初始化状态下,约定头尾指针均指向头结点  queue->tail=queue->head;  return queue;}

判空:

int isnull_queue(queue_t* queue) {    return (queue->head->next==NULL&&queue->tail->next==NULL);//通过链表判断  //return queue->head == queue->tail; //通过头尾判断}

入队:通过尾部入队,利用尾指针增加

68826d28dc14b7695cfb668987e8da0d.png

int push_queue(queue_t* queue,int data) {  if(queue==NULL)    return -1;  //1 申请新节点的空间  list_t* newnode=malloc(sizeof(list_t));  //2 存入数据  newnode->data=data;  newnode->next=NULL;  //3 将新节点连接到链表中  queue->tail->next=newnode;  //4 修改尾指针tail的指向,指向新的尾巴结点  queue->tail=newnode;  return 0;}

出队:

int pop_queue(queue_t* queue,int* data) {  if(queue==NULL||isnull_queue(queue))    return -1;  //备份出队的结点  list_t* temp=queue->head->next;  //获取出队的数据  *data=temp->data;  //数据出队  queue->head->next=temp->next;  //如果出队数据后,队列为空,要找回尾指针tail的指向  if(temp->next==NULL)    queue->tail=queue->head;  //释放出队数据的结点  free(temp);  return 0;}

假打印:

int print_queue_fake(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  //标记头结点  list_t* temp=queue->head;  //循环打印数据  while(temp->next!=NULL) { //跳过头结点    printf("%3d ",temp->next->data);    temp=temp->next;   }  printf("\n");  return 0;}

真打印(需要出队):

int print_queue_real(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  //创建一个临时队列  queue_t* temp=create_queue();    int data;  while(!isnull_queue(queue)) {    //pop_queue 出队 打印    pop_queue(queue,&data);     printf("%3d ",data);    //push_queue 入临时的队列存放    push_queue(temp,data);  }  printf("\n");    while(!isnull_queue(temp)) { //数据放回原队列    pop_queue(temp,&data);    push_queue(queue,data);    }  //销毁临时队列  destroy_queue(&temp);    return 0;}

真逆打印(两个栈实现一个队列,和顺序队列一样):

9a3d59135ba632e19731d478d10b7c2f.png

int reprintf_queue_real(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return -1;  int *s1=malloc(sizeof(int)*length_queue(queue));  int *s2=malloc(sizeof(int)*length_queue(queue));  int top1=-1;  int top2=-1;  int data;  while(!isnull_queue(queue)) {    pop_queue(queue,&data); //出队    s1[++top1]=data; //入栈  第1步  }  while(top1!=-1) {    data=s1[top1--]; //出栈,此时已倒序   第2步    printf("%3d ",data);    s2[++top2]=data; //入第二个栈     }  while(top2!=-1) {    data=s2[top2--];//出栈,顺序再次逆,变为正  第3步    push_queue(queue,data); //入队  }  printf("\n");  //销毁  free(s1);  free(s2);  return 0;}

长度:

int length_queue(queue_t* queue) {  if(queue==NULL||isnull_queue(queue))    return 0;  //标记头结点  list_t* temp=queue->head;  //定义保存长度的变量  int sum=0;  //循环判断,只要队列不为空,sum++  while(temp->next!=NULL) { //跳过头结点    sum++;    temp=temp->next;    }  //返回长度  return sum;}

清空:

int clear_queue(queue_t* queue) {  if(queue==NULL)    return -1;  int data;  //只要不为空,就执行出队数据操作  while(!isnull_queue(queue)) {    pop_queue(queue,&data);    }    return 0;}

销毁:

int destroy_queue(queue_t** queue) {  if(*queue==NULL)    return -1;  //清空  if(!isnull_queue(*queue)) {    clear_queue(*queue);  }  //释放  free((*queue)->head);  free(*queue);  *queue=NULL;  return 0;}

main函数:

int main(int argc, const char *argv[]){  queue_t* queue=create_queue();  int i;  for(i=1;i<=20;i++) {    push_queue(queue,i);    print_queue_fake(queue);    }#if 0  int data;  for(i=1;i<=20;i++) {    if(pop_queue(queue,&data)==0)      printf("popdata:%d\n",data);    print_queue_fake(queue);  }#endif  printf("real printf:");  print_queue_real(queue);  printf("real reprintf:");  reprint_queue_real(queue);  printf("length_queue:%d\n",length_queue(queue));    if(clear_queue(queue)==0) {    printf("success cleared!\n");    printf("length_queue:%d\n",length_queue(queue));  }  push_queue(queue,888);  push_queue(queue,666);  print_queue_fake(queue);    destroy_queue(&queue);  if(queue==NULL) {    printf("success destroyed!\n");  }    return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值