队列

1、队列的定义
队列(Queue)是一种先进先出的线性表(First In Frist Out,简称FIFO)。只允许在表的一端(front)进行删除,另一端(rear)进行插入。
队首(front):只允许进行删除的一端
队尾(rear):只允许进行插入的一端
队列中没有元素的时候成为空队列。在空队列中依次加入元素a1,a2,...,an之后,a1是队首元素,an是队尾元素。所以退出队列的次序是a1,a2,...,an,按照先进先出的原则进行。

队列.jpg

2.队列的主要操作
(1)清空队列
(2)判断是否为空
(3)元素的个数
(4)入队列
(5)出队列
(6)取队头元素
3.顺序实现队列
队列数组实现.png

存在问题
设数组长度为M,则:
当front=0,rear=M,再有元素入队时发生溢出----真溢出
当front!=0,rear=M,再有元素入队时发生溢出----假溢出
解决方案
循环队列:把队列设想成环形,让sq[0]接在sq[m-1]之后,若rear+1==M,则令rear=0。
循环队列.png

顺序实现队列
(1)

struct DATA{
 string name;
 int age;
};
struct SQType
{
 DATA data[QUEUELEN];//队列数组
 int head;//队头
 int tail;//队尾
};

定义了队列结构的最大长度是QUEUELEN,队列结构的数据元素类型DATA,队列结构的数据结构类型SQType。在数据结构SQType中,data为数据元素,head是队首序号,tail是队尾序号。当head=0时,队列为空,当tail=QUEUELEN时表示队列满。

(2)初始化队列数据
<1>按符号常量QUEUELEN指定的大小申请一段内存空间,用来保存队列中的数据。
<2>设置head=0和tail=0,表示一个空栈。

SQType *SQTypeInit()
{
 SQType *q;
 if(q = new SQType)//申请队列的内存空间
 {
   q -> head = 0;//队首
   q -> tail = 0;//队尾
   return q;
 }
 else
 {
   return NULL;//返回空
 }
}

(3)判断空队列
判断空队列是判断一个队列结构是否为空。如果是空,此时队列可以进行入队操作,不可以进行出队操作。

int SQTypeIsEmpty(SQType *q)
{
 return(q -> head == q -> tail);
}

(4)判断满队列
判断满队列就是判断一个队列结构是否为满。满队列不可以进行入队操作,可以进行出队操作

int SQTypeIsFull(SQType *q)
{
 return(q -> tail == QUEUELEN);
}

(5)清空队列

void SQTypeClear(SQType *q)
{
 q -> head =0;
 q -> tail =0;
}

(6)释放空间
释放空间是释放队列结构所占用的内存空间,前面用new关键字分配的内存单元,可以用delete释放。

void SQTypeFree(SQType *q)
{
 if(q != NULL) delete q;
}

(7)入队列
<1>判断队尾,如果tail等于QUEUELEN,队列满不能插入数据。
<2>设置tail=tail+1
<3>将入队元素保存到tail指向的位置

int InSQType(SQType *q,DATA data)
{
 if(q -> tail == QUEUELEN)
  {
    cout<<"队列已满,操作失败!!"<<endl;
  }
 else
 {
    q -> data[q -> tail++] = data;
     return 1;
 }
}

(8)出队列
<1>判断队首head,如果head等于tail,则表示队列为空
<2>从队列首部取出队头元素(实际返回队头元素的指针)
<3>修改队首head的序号,指向后一个元素

DATA *OutSQType(SQType *q)
{
  if(q -> tail == q -> head)
    {
      cout<<"队列已空!操作失败!"<<endl;
      exit(0);
    }
  else
  {
    return &(q -> data[q -> head++]);
  }
}

(9)读节点数据
读节点数据就是读队头的数据

DATA *PeekSQType(SQType *q)
{
  if(SQTypeIsEmpty(q))
  {
    cout<<"空对列"<<endl;
    return NULL;
  }
  else
  {
    return &(q -> data[q -> head]);
  }
}

(10)计算队列长度
计算队列长度就是计算该队列中数据节点的个数。用队尾序号减去队首序号。

int SQTypeLen(SQType *q)
{
  return(q -> tail - q -> head);
}

源代码:http://pan.baidu.com/s/1qYKZG76
截图:

结果.png

4.链表实现队列

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

#define Error(str) FatalError(str)
#define FatalError(str) fprintf(stderr, "%s\n", str),exit(1)

typedef int ElementType;
#define MAXQUEUE 10

typedef struct node
{
  ElementType data;
  struct node* nextNode;
}Node;

typedef struct queue
{
  Node* front; //队首指针
  Node* rear;//队尾指针
  int items;//队列中项目个数
}*ptrQueue;

typedef ptrQueue Queue;
int IsEmpty(Queue q);
int IsFull(Queue q);
Queue CreateQueue(void);
void DisposeQueue(Queue q);
void MakeEmpty(Queue q);
void Enqueue(ElementType x, Queue q);
ElementType Front(Queue q);
void Dequeue(Queue q);
ElementType FrontAndDequeue(Queue q);

int main(void)
{
  Queue sqQueue;
  
  sqQueue = CreateQueue();
  if(IsEmpty(sqQueue))
    printf("创建一个空队列");
  
  int value = 0;
  printf("队列中的数据为(front -> rear): \n");
  while(!IsFull(sqQueue))
  {
    Enqueue(value*value, sqQueue);//入队
    printf("%d", value*value);
    value++;
  }
  printf("队列已满\n");

  ElementType frontQueue;
  frontQueue = Front(sqQueue);
  printf("对头元素为: %d\n",frontQueue);
  
  Dequeue(sqQueue);
  frontQueue = Front(sqQueue);
  printf("执行出队操作Dequeue之后,对头元素是: %d\n",frontQueue);
  DisposeQueue(sqQueue);
  return 0;
}

/***是否为空***/
int IsEmpty(Queue q)
{
  return q -> items == 0;
}

/***是否已满***/
int IsFull(Queue q)
{
  return q -> items == MAXQUEUE;
}

/***创建队列***/
Queue CreateQueue(void)
{
  Queue q;
  
  q = (Queue)malloc(sizeof(struct queue));
  if(NULL == q)
    Error("空间不足,队列分配内存失败!");

  q -> front = (Node*)malloc(sizeof(Node));
  if(NULL == q -> front)
    Error("空间不足,队列首节点内存分配失败!");
  
  q -> rear = (Node*)malloc(sizeof(Node));
  if(NULL == q -> rear)
    Error("空间不足,队列尾节点内存分配失败!");

  q -> items = 0;

  return q;
}

/***释放队列***/
void DisposeQueue(Queue q)
{
  MakeEmpty(q);
  free(q);
}

/***使队列为空***/
void MakeEmpty(Queue  q)
{
  if(q == NULL)
    Error("必须先使用CreateQueue创建队列!");

  while(IsEmpty(q))
    Dequeue(q);
}

/***入队***/
void Enqueue(ElementType x, Queue q)
{
  if(IsFull(q))
    Error("队列已满");
  
  Node* pnode;
  pnode = (Node*)malloc(sizeof(Node));
  if(NULL == pnode)
    Error("新节点分配内存失败!");

  pnode -> data = x;
  pnode -> nextNode = NULL;
  if(IsEmpty(q))
    q -> front = pnode;//队列为空数据插入队首位置
  else
    q -> rear -> next = pnode;//队列不为空,元素放在队尾指针的下一个位置
  q -> rear = pnode;//队列尾指针指向pnode节点
  q -> items++;//队列项目数加1

  return;
}

/***出队***/
void Dequeue(Queue q)
{
  if(IsEmpty(q))
    Error("队列本身为空");

  Node* pnode;
  pnode = q -> rear;
  q -> front = q -> front -> nextNode;
  free(pnode);

  q -> items--;
  if(q -> items == 0)
    q -> rear = NULL;

  return;
}

/***返回队列头元素***/
ElementType Front(Queue q)
{
  if(!IsEmpty(q))
    return q -> front -> data;
  Error("队列为空\n");

  return 0;
}

/***返回对头元素并使对头元素出队***/
ElementType FrontAndDequeue(Queue q)
{
  ElementType x;
  
  if(IsEmpty(q))
    Error("队列为空\n");
  else
  {
    q -> items--;
     x =q -> front -> data;
     q -> front = q -> front -> nextNode;
  }
  
  return x;
}

源代码:http://pan.baidu.com/s/1o8jkZcI
截图:

单链表实现队列.png

3.不使用动态创建内存(malloc)而是申请固定地址来实现队列

typedef struct qq_link_struct
{
  struct qq_link_struct *ptr;//相当于nextNode下一个节点
}qq_link_type;

typedef struct qq_struct
{
  qq_link_type head;//队列头指针
  qq_link_type tail;//队列尾指针
   int cnt;//记录队列数据个数
}qq_type;

(1)初始化队列

qq_type* qq_init(qq_type *q_ptr)
{
  q_ptr -> head.ptr = &q_ptr -> head;//
  q_ptr -> tail.ptr = &q_ptr -> head;//初始时队列为空,q_ptr的头指针。尾指针都指向head
  q_ptr -> cnt = 0;
  return q_ptr;
}

(2)插入数据

/***队列尾部只能进行插入**/
void qq_put(qq_type *q_ptr,qq_link_type * link_ptr)
{
  link_ptr -> ptr = &q_ptr -> head;//link指向插入数据
  q_ptr -> tail.ptr -> ptr = link_ptr;//队列尾部插入数据
  q_ptr -> tail.ptr = link_ptr;//改变队列尾指针
  q_ptr -> cnt++;
}

(3)取出数据

/***队列头部只能取数据***/
void* qq_get(qq_type * q_ptr)
{
  qq_link_type *ret_ptr = 0;
  if(q_ptr -> cnt > 0 )//cnt大于0队列才有数据可以取出来
  {
    ret_ptr = q_ptr -> head.ptr;//存放取出的数据
    q_ptr -> head.ptr = ret_ptr -> ptr;//改变队列头指针
    q_ptr -> cnt--;
    if(q_ptr -> cnt ==0)
    {
      q_ptr -> tail.ptr = &q_ptr -> head;//当队列中没有数据尾指针指向队列头
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容