浅谈数据结构之链队列(六)

  前面我们讲了队列的顺序存储结构,现在我们来看看队列的链式存储结构。队列的链式存储其实就是线性表的单链表结构,只不过它是尾进头出而已,通常我们把它简称为链队列。为了操作上的方便,我们将队头指针front指向链队列的头结点,而队尾指针rear则指向终端结点。注意:当队列为空时,指针front和rear都指向头结点。

  在这里,我们再介绍一下循环队列。循环队列是为了避免数组插入与删除数据时需要移动数据而引入的,我们一般把队列的这种头尾相接的顺序存储结构称为循环队列。对于循环队列和链队列相比较来说,循环队列使得队头和队尾在数组中循环变化,解决了移动数据时所需要的时间损耗,因此它的时间复杂度为0(1);而链队列事先并不需要预估队列的长度,也没有存储元素个数和空间浪费的问题,所以在空间上,链队列更加灵活,方便。

  链队列的入队操作其实就是在链表尾插入结点,而出队操作则是将头结点的后继结点出队,同时将头结点的后继改为它后面的结点;若链表除头结点外只剩下一个元素,则需将指针rear指向头结点,具体操作源程序代码如下所示:

  1 #include <stdio.h>
  2 #include <stdlib.h> 
  3 #include <math.h>
  4 
  5 #define OK 1
  6 #define ERROR 0
  7 #define TRUE 1
  8 #define FALSE 0
  9 
 10 #define MAXSIZE 20            /* 存储空间初始分配量 */
 11 
 12 typedef int Status; 
 13 typedef int QElemType;        /* QElemType类型根据实际情况而定,这里假设为int */
 14 
 15 typedef struct QNode          /* 结点结构 */
 16 {
 17    QElemType data;
 18    struct QNode *next;
 19 }QNode,*QueuePtr;
 20 
 21 typedef struct                /* 队列的链表结构 */
 22 {
 23    QueuePtr front,rear;       /* 队头、队尾指针 */
 24 }LinkQueue;
 25 
 26 Status visit(QElemType c)
 27 {
 28     printf("%d ",c);
 29     return OK;
 30 }
 31 
 32 /* 构造一个空队列Q */
 33 Status InitQueue(LinkQueue *Q)
 34 { 
 35     Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));
 36     if(!Q->front)
 37         exit(OVERFLOW);
 38     Q->front->next=NULL;
 39     return OK;
 40 }
 41 
 42 /* 将Q清为空队列 */
 43 Status ClearQueue(LinkQueue *Q)
 44 {
 45     QueuePtr p,q;
 46     Q->rear=Q->front;
 47     p=Q->front->next;
 48     Q->front->next=NULL;
 49     while(p)
 50     {
 51         q=p;
 52         p=p->next;
 53         free(q);
 54     }
 55     return OK;
 56 }
 57 
 58 /* 求队列的长度 */
 59 int QueueLength(LinkQueue Q)
 60 { 
 61     int i=0;
 62     QueuePtr p;
 63     p=Q.front;
 64     while(Q.rear!=p)
 65     {
 66         i++;
 67         p=p->next;
 68     }
 69     return i;
 70 }
 71 
 72 /* 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR */
 73 Status GetHead(LinkQueue Q,QElemType *e)
 74 { 
 75     QueuePtr p;
 76     if(Q.front==Q.rear)
 77         return ERROR;
 78     p=Q.front->next;
 79     *e=p->data;
 80     return OK;
 81 }
 82 
 83 
 84 /* 插入元素e为Q的新的队尾元素 */
 85 Status EnQueue(LinkQueue *Q,QElemType e)
 86 { 
 87     QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
 88     if(!s)                        /* 存储分配失败 */
 89         exit(OVERFLOW);
 90     s->data=e;
 91     s->next=NULL;
 92     Q->rear->next=s;              /* 把拥有元素e的新结点s赋值给原队尾结点的后继 */
 93     Q->rear=s;                    /* 把当前的s设置为队尾结点,rear指向s */
 94     return OK;
 95 }
 96 
 97 /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
 98 Status DeQueue(LinkQueue *Q,QElemType *e)
 99 {
100     QueuePtr p;
101     if(Q->front==Q->rear)
102         return ERROR;
103     p=Q->front->next;             /* 将欲删除的队头结点暂存给p */
104     *e=p->data;                   /* 将欲删除的队头结点的值赋值给e */
105     Q->front->next=p->next;       /* 将原队头结点的后继p->next赋值给头结点后继 */
106     if(Q->rear==p)                /* 若队头就是队尾,则删除后将rear指向头结点 */
107         Q->rear=Q->front;
108     free(p);
109     return OK;
110 }
111 
112 /* 从队头到队尾依次对队列Q中每个元素输出 */
113 Status QueueTraverse(LinkQueue Q)
114 {
115     QueuePtr p;
116     p=Q.front->next;
117     while(p)
118     {
119         visit(p->data);
120         p=p->next;
121     }
122     printf("
");
123     return OK;
124 }
125 
126 int main()
127 {
128     int i;
129     QElemType e;
130     LinkQueue q;
131     
132     i=InitQueue(&q);
133     printf("1.初始化后队列后,队列的长度:Q.length=%d
",QueueLength(q));
134     
135     EnQueue(&q,-5);
136     EnQueue(&q,3);
137     EnQueue(&q,8);
138     EnQueue(&q,10);
139     EnQueue(&q,16);
140     EnQueue(&q,36);
141     printf("2.插入6个元素后,队列的长度:Q.length=%d
",QueueLength(q));
142     printf("3.队列的元素输出依次为:");
143     QueueTraverse(q);
144     
145     i=GetHead(q,&e);
146     if(i==OK)
147          printf("4.此时队列的队头元素是:%d
",e);
148          
149     DeQueue(&q,&e);
150     i=GetHead(q,&e);
151     if(i==OK)
152         printf("5.删除队列的队头元素后,新的队头元素是:%d
",e);
153         
154     DeQueue(&q,&e);
155     printf("6.继续删除队头元素后,队列的长度:Q.length=%d
",QueueLength(q));
156     printf("7.队列的元素输出依次为:");
157     QueueTraverse(q);
158         
159     ClearQueue(&q);
160     printf("8.清空队列后,q.front=%u q.rear=%u q.front->next=%u
",q.front,q.rear,q.front->next);
161     
162     return 0;
163 }
原文地址:https://www.cnblogs.com/mix88/p/6180622.html