队列的链式存储结构

队列的链式存储结构

所谓队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已。

为了操作方便,我们将队头指针指向链队列的头结点,而队尾指针指向终点元素,注意这个时候不是尾部元素的下一个了。如图:

空队列时,头指针front和尾指针rear都指向头结点。

链队列的结构为

1 typedef struct QNode   //节点结构
2 {
3     int data;
4     QNode* next;
5 }QNode;
6 typedef struct QNode* QueuePtr;
7 typedef struct{               //队列的链表结构
8     QueuePtr front,rear;
9 }LinkQueue;

 队列初始化操作

 1 /*链队列初始化操作,初始化头结点*/
 2 int InitLinkQueue(LinkQueue* Q){
 3     if(!Q)
 4         return 0;
 5     QueuePtr s =(QueuePtr)malloc(sizeof(QNode));
 6     s->next=NULL;
 7     Q->front=Q->rear=s; //置空
 8     return 0;
 9 
10 }

队列使用前必须初始化,申请头结点内存空间。

入队操作

 1 /*入队操作*/
 2 int EnQueue(LinkQueue* Q,int e){
 3     QueuePtr s =(QueuePtr)malloc(sizeof(QNode));  //申请新节点空间
 4     if(!s)
 5         return 0;
 6     s->data=e;      //赋值
 7     //s->next=Q->rear->next;   //并初始化,与s->next=NULL相同    
 8     s->next=NULL;
 9     Q->rear->next=s;
10 
11     Q->rear=s;
12     return e;
13 }

入队的操作是将新节点指向rear 的next ,然后再将rear 的next指向新节点(类似单链表的插入),最后确记要把rear移动到新节点

出队操作

 1 /*出队操作*/
 2 int DeQueue(LinkQueue* Q){
 3 
 4     int e;
 5     QueuePtr p;
 6     p=Q->front->next;    //指向第一个节点
 7     if(p){
 8         Q->front->next=p->next;    //头结点下移
 9         free(p);             //释放内存
10         p=Q->front->next;   //p再移到头结点下
11     }
12     else if(p = Q->rear)          //空队列时
13         Q->front = Q->rear;
14 
15     return e;
16 }

使用一个指针p指向头结点的下一位,然后移动头结点到p的next,再然后释放p的内存,这就释放的一个节点的空间,此时p再次移动到头结点的下一位,依次进行...

遍历队元素

1 /*遍历队列*/
2 void TraverseQueue(LinkQueue* Q){
3     QueuePtr p;
4     p = Q->front->next;
5     while(p){
6         printf("%d ",p->data);
7         p=p->next;
8     }    
9 }

遍历队元素的确记不要去移动front和rear指针的而位置,所以要再新建一个指针来遍历。

 清空队

 1 /*清空链队列*/
 2 int ClearLinkQueue(LinkQueue* Q){
 3 
 4     QueuePtr p;
 5 
 6     p = Q->front->next;  //p指向头结点下一个
 7     while(p){
 8         Q->front->next=p->next;   //队头移动
 9         if(Q->rear==p)   //删到队尾了
10             Q->front = Q->rear;  //队列置空
11         else if(Q->front=Q->rear)  //循环退出
12             return 0;    
13         free(p);   //释放内存
14         p=Q->front->next;   //继续移动
15     }
16     return 1;
17 }

再清空队列的循环中确记要加上循环结束的出口,否则将陷入死循环,即当Q->real==Q->front时,队列为空 。其中指针的移动类似于出队的操作相同。

主要代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 typedef struct QNode   //节点结构
  5 {
  6     int data;
  7     QNode* next;
  8 }QNode;
  9 typedef struct QNode* QueuePtr;
 10 
 11 typedef struct{               //队列的链表结构
 12     QueuePtr front,rear;
 13 }LinkQueue;
 14 
 15 /*链队列初始化操作,初始化头结点*/
 16 int InitLinkQueue(LinkQueue* Q){
 17     if(!Q)
 18         return 0;
 19     QueuePtr s =(QueuePtr)malloc(sizeof(QNode));
 20     s->next=NULL;
 21     Q->front=Q->rear=s; //置空
 22     return 0;
 23 }
 24 
 25 /*入队操作*/
 26 int EnQueue(LinkQueue* Q,int e){
 27     QueuePtr s =(QueuePtr)malloc(sizeof(QNode));
 28     if(!s)
 29         return 0;
 30     s->data=e;      //赋值
 31     //s->next=Q->rear->next;   //并初始化,与s->next=NULL相同    
 32     s->next=NULL;
 33     Q->rear->next=s;
 34 
 35     Q->rear=s;
 36     return e;
 37 }
 38 
 39 /*清空链队列*/
 40 int ClearLinkQueue(LinkQueue* Q){
 41 
 42     QueuePtr p;
 43 
 44     p = Q->front->next;  //p指向头结点下一个
 45     while(p){
 46         Q->front->next=p->next;   //队头移动
 47         if(Q->rear==p)   //删到队尾了
 48             Q->front = Q->rear;  //队列置空
 49         else if(Q->front=Q->rear)  //循环退出
 50             return 0;    
 51         free(p);   //释放内存
 52         p=Q->front->next;   //继续移动
 53     }
 54     return 1;
 55 }
 56 
 57 
 58 /*队列是否为空*/
 59 int ElmptyQueue(LinkQueue* Q){
 60     QueuePtr p;
 61     p=Q->front->next;
 62     if(p)
 63         return 0;
 64     else 
 65         return 1;
 66 }
 67 
 68 /*获取队列长度*/
 69 int QueueLength(LinkQueue* Q){
 70     int count=0;
 71     QueuePtr p;
 72     p=Q->front->next;
 73     while(p){
 74         count++;
 75         p=p->next;
 76     }        
 77     return count;
 78 }
 79 
 80 /*出队操作*/
 81 int DeQueue(LinkQueue* Q){
 82 
 83     int e;
 84     QueuePtr p;
 85     p=Q->front->next;    //指向第一个节点
 86     if(p){
 87         Q->front->next=p->next;    //头结点后移
 88         free(p);             //释放内存
 89         p=Q->front->next;   //p再移到头结点下
 90     }
 91     else if(p = Q->rear)          //空队列时
 92         Q->front = Q->rear;
 93 
 94     return e;
 95 }
 96 
 97 /*遍历队列*/
 98 void TraverseQueue(LinkQueue* Q){
 99     QueuePtr p;
100     p = Q->front->next;
101     while(p){
102         printf("%d ",p->data);
103         p=p->next;
104     }    
105 }
106 
107 int main(){
108 
109     LinkQueue s;
110     InitLinkQueue(&s);
111     printf("入队10个元素 :\n");
112     for(int i=0;i<10;i++)
113     printf("%d ",EnQueue(&s,i));
114     printf("\n");
115 
116     printf("遍历队列\n");
117     TraverseQueue(&s);
118     printf("\n");
119 
120     printf("队元素个数");
121     printf("个数:%d\n",QueueLength(&s));
122     printf("出队一个元素\n");
123     DeQueue(&s);
124     printf("队元素个数");
125     printf("个数:%d\n",QueueLength(&s));
126     
127     printf("是否队列为空(1:0):%d\n ",ElmptyQueue(&s));
128 
129     printf("清空队列...");
130     ClearLinkQueue(&s);
131     printf("个数:%d\n",QueueLength(&s));
132     return 0;
133 }

 

扫描二维码关注公众号,回复: 5041403 查看本文章

 链式存储结构比顺序结构难操作,特别要注意指针的指向和指向内存的有效性。

比较循环队列和链队列的差异性:

从时间上:两者操作都是O(1),即常数时间,不过循环队列是事先申请好空间,使用期间不能释放,而对于链队列,每次申请和释放节点也会产生一些时间上的开销

如果入队和出队频繁的话,还是存在细微差异性的,

从空间:循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题了,而链队列不存在此问题,所以在空间上,链队列更加灵活。

 附上Java代码 

1 package linkqueue;
2 
3 public class QNode {
4     int data;
5     QNode next;
6 }
View Code
 1 package linkqueue;
 2 public class LinkQueue {
 3 
 4     QNode front, rear;
 5 
 6     /**
 7      * 初始化队列
 8      */
 9     public void InitLinkQueue(LinkQueue Q) {
10         QNode node = new QNode();
11         node.next = null;
12         Q.front = Q.rear = node;
13     }
14 
15     /**
16      * 入队
17      */
18     public void EnLinkQueue(LinkQueue Q, int e) {
19         QNode node = new QNode();
20         node.data = e;
21         node.next = Q.rear.next;
22         Q.rear.next = node;
23         Q.rear = node;
24     }
25 
26     /**
27      * 出队
28      */
29     public int DeLinkQueue(LinkQueue Q) {
30         int e;
31         QNode node;
32         node = Q.front.next;
33 
34         if (node != null) {
35             e = node.data;
36             Q.front.next = node.next;
37             node = Q.front.next;
38             return e;
39         } else if (node == Q.rear) {
40             Q.rear = Q.front;
41         }
42         return 0;
43     }
44 
45     /**
46      * 清空队
47      */
48     public void ClearLinkQueue(LinkQueue Q) {
49         QNode node;
50         node = Q.front.next;
51         if (node == Q.rear)
52             Q.rear = Q.front = null;
53         while (node != null) {
54             Q.front.next = node.next;
55             node = Q.front.next;
56         }
57 
58     }
59 
60     /**
61      * 返回队列长度
62      */
63     public int GtLinkQueue(LinkQueue Q) {
64         int count = 0;
65         QNode node;
66         node = Q.front.next;
67         while (node != null) {
68             count++;
69             node = node.next;
70         }
71         return count;
72     }
73 
74     /**
75      * 遍历队元素
76      */
77     public void TraverseList(LinkQueue Q) {
78         QNode node;
79         node = Q.front.next;
80         while (node != null) {
81             System.out.print(node.data + " ");
82             node = node.next;
83         }
84     }
85 
86 }
View Code
 1 package linkqueue;
 2 
 3 public class Test {
 4 
 5     public static void main(String[] args) {
 6         LinkQueue queue = new LinkQueue();
 7         System.out.println("初始化队列...");
 8         queue.InitLinkQueue(queue);
 9         System.out.println("入队10个元素...");
10         for (int i = 0; i < 10; i++)
11             queue.EnLinkQueue(queue, i);
12         System.out.println("遍历队列元素...");
13         queue.TraverseList(queue);
14         System.out.println("");
15 
16         System.out.println("出队一个元素..." + queue.DeLinkQueue(queue));
17         System.out.println("再出队一个元素..." + queue.DeLinkQueue(queue));
18 
19         System.out.println("元素个数..." + queue.GtLinkQueue(queue));
20 
21         System.out.println("清空队列");
22         queue.ClearLinkQueue(queue);
23         System.out.println("元素个数..." + queue.GtLinkQueue(queue));
24 
25     }
26 
27 }
View Code

 完毕 -  。- 

猜你喜欢

转载自www.cnblogs.com/liuzeyu12a/p/10312115.html