数据结构——队列
数据结构——队列
浅谈
在队列的形成过程中,可以利用线性链表的原理,来生成一个队列。
基于链表的队列,要动态创建和删除节点,效率较低,但是可以动态增长。
队列采用的FIFO(first in first out),新元素(等待进入队列的元素)总是被插入到链表的尾部,而读取的时候总是从链表的头部开始读取。每次读取一个元素,释放一个元素。所谓的动态创建,动态释放。因而也不存在溢出等问题。由于链表由结构体间接而成,遍历也方便。 队列又称为先进先出(FIFO—first in first out)线性表。
第一个程序就是由单链表删减形成的链式队列
链式队列
创建队列
PNODE create_queue(void) { int len; //用来存放有效节点的个数 int i; int val; //用来临时存放用户输入的结点的值 //分配了一个不存放有效数据的头结点 PNODE pHead = (PNODE)malloc(sizeof(Node)); if (NULL == pHead) { printf("分配失败, 程序终止!\n"); exit(-1); } PNODE pTail = pHead; pTail->pNext = NULL; printf("请输入您需要生成的队列节点的个数: len = "); scanf_s("%d", &len); for (i = 0; i < len; ++i) { printf("请输入第%d个节点的值: ", i + 1); scanf_s("%d", &val); PNODE pNew = (PNODE)malloc(sizeof(Node)); if (NULL == pNew) { printf("分配失败, 程序终止!\n"); exit(-1); } pNew->data = val; pTail->pNext = pNew; pNew->pNext = NULL; pTail = pNew; } return pHead; }
遍历队列
void Travers(PNODE pHead) { PNODE p = pHead->pNext; while (NULL != p) { printf("%d", p->data); p = p->pNext; } return; }
判断为空
bool is_empty(PNODE pHead) { if (NULL == pHead->pNext) return true; else return false; }
队列长度
int length_queue(PNODE pHead) { PNODE p = pHead->pNext; int len = 0; while (NULL != p) { len++; p = p->pNext; } return len; }
入队
bool InQueue(PNODE pHead, int val) { PNODE p = pHead; while (NULL !=p->pNext) { p = p->pNext; } PNODE pNew = (PNODE)malloc(sizeof(Node)); if (NULL == p) { printf("失败"); exit(-1); } pNew->data = val; p->pNext = pNew; pNew->pNext = NULL; return true; }
出队
bool OutQueue(PNODE pHead, int* val) { PNODE q = pHead->pNext; *val = q->data; pHead->pNext = pHead->pNext->pNext; free(q); q = NULL; return true; }
完整程序
# include <stdio.h> # include <malloc.h> # include <stdlib.h> typedef struct Node { int data; //数据域 struct Node* pNext; //指针域 } * PNODE; //NODE等价于struct Node PNODE等价于struct Node * //函数声明 PNODE create_queue(void); //创建队列 void Travers(PNODE pHead); //遍历队列 bool is_empty(PNODE pHead); //判断队列是否为空 int length_queue(PNODE); //求队列长度 bool InQueue(PNODE pHead, int pos, int val); //入队 bool OutQueue(PNODE pHead, int pos, int* pVal); //出队 PNODE create_queue(void) { int len; //用来存放有效节点的个数 int i; int val; //用来临时存放用户输入的结点的值 //分配了一个不存放有效数据的头结点 PNODE pHead = (PNODE)malloc(sizeof(Node)); if (NULL == pHead) { printf("分配失败, 程序终止!\n"); exit(-1); } PNODE pTail = pHead; pTail->pNext = NULL; printf("请输入您需要生成的队列节点的个数: len = "); scanf_s("%d", &len); for (i = 0; i < len; ++i) { printf("请输入第%d个节点的值: ", i + 1); scanf_s("%d", &val); PNODE pNew = (PNODE)malloc(sizeof(Node)); if (NULL == pNew) { printf("分配失败, 程序终止!\n"); exit(-1); } pNew->data = val; pTail->pNext = pNew; pNew->pNext = NULL; pTail = pNew; } return pHead; } void Travers(PNODE pHead) { PNODE p = pHead->pNext; while (NULL != p) { printf("%d", p->data); p = p->pNext; } return; } bool is_empty(PNODE pHead) { if (NULL == pHead->pNext) return true; else return false; } int length_queue(PNODE pHead) { PNODE p = pHead->pNext; int len = 0; while (NULL != p) { len++; p = p->pNext; } return len; } bool InQueue(PNODE pHead, int val) { PNODE p = pHead; while (NULL !=p->pNext) { p = p->pNext; } PNODE pNew = (PNODE)malloc(sizeof(Node)); if (NULL == p) { printf("失败"); exit(-1); } pNew->data = val; p->pNext = pNew; pNew->pNext = NULL; return true; } bool OutQueue(PNODE pHead, int* val) { PNODE q = pHead->pNext; *val = q->data; pHead->pNext = pHead->pNext->pNext; free(q); q = NULL; return true; } int main(void) { PNODE pHead = NULL; int val; pHead = create_queue(); Travers(pHead); printf("\n"); InQueue(pHead,1); InQueue(pHead,2); OutQueue(pHead, &val); OutQueue(pHead, &val); OutQueue(pHead, &val); Travers(pHead); return 1; }
循环队列
为什么要有循环队列
为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。
被掰弯的单链表就是循环链表

由上图运行一下程序可自行体会,上边说的把链式队列掰弯其实不准确,准确的应该是把数组链表掰弯形成的循环队列,注意头结点的存在!!!!循环队列比链式队列相对更安全更简洁;
完整程序
# include <stdio.h> # include <malloc.h> #define l_queue 6 //所需队列长度 typedef struct Queue { int* pBase; //生成队列的大小 int front; //队尾 int rear; //队头 }QUEUE; void init(QUEUE*); //初始化 bool in_queue(QUEUE*, int val); //入队 void traverse_queue(QUEUE*); //遍历队列 bool full_queue(QUEUE*); //判断是否为满 bool out_queue(QUEUE*, int*); //出队 bool emput_queue(QUEUE*); //判断是否位空 int main(void) { printf(" pQ->rear pQ->pBase pQ->front \n"); printf(" 队头 队列大小 队尾 \n"); printf("*******************\n"); QUEUE Q; int val; init(&Q); in_queue(&Q, 10); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 20); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 30); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 40); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 50); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 60); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 70); printf("当前队列内容为:"); traverse_queue(&Q); in_queue(&Q, 80); printf("当前队列内容为:"); traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); if (out_queue(&Q, &val)) { printf("当前队列内容为:"); } else { printf("出队失败!\n"); } traverse_queue(&Q); return 0; } void init(QUEUE* pQ) { pQ->pBase = (int*)malloc(sizeof(int) * l_queue); pQ->front = 0; pQ->rear = 0; } bool full_queue(QUEUE* pQ) { if ((pQ->rear + 1) % l_queue == pQ->front) return true; else return false; } bool in_queue(QUEUE* pQ, int val) { if (full_queue(pQ)) { return false; } else { printf(" %d %d %d \n", pQ->rear, pQ->pBase, pQ->front); pQ->pBase[pQ->rear] = val; pQ->rear = (pQ->rear + 1) % l_queue; printf(" %d %d %d \n", pQ->rear, pQ->pBase, pQ->front); printf("*******************\n"); return true; } } void traverse_queue(QUEUE* pQ) { int i = pQ->front; while (i != pQ->rear) { printf("%d ", pQ->pBase[i]); i = (i + 1) % l_queue; } printf("\n"); return; } bool emput_queue(QUEUE* pQ) { if (pQ->front == pQ->rear) return true; else return false; } bool out_queue(QUEUE* pQ, int* pVal) { if (emput_queue(pQ)) { return false; } else { printf(" %d %d %d \n", pQ->rear, pQ->pBase, pQ->front); pQ->front = (pQ->front + 1) % l_queue; printf(" %d %d %d \n", pQ->rear, pQ->pBase, pQ->front); printf("*******************\n"); return true; } }
定义声明
# include <stdio.h>
# include <malloc.h>
#define l_queue 6 //所需队列长度
typedef struct Queue
{
int* pBase; //生成队列的大小
int front; //队尾
int rear; //队头
}QUEUE;
void init(QUEUE*); //初始化
bool in_queue(QUEUE*, int val); //入队
void traverse_queue(QUEUE*); //遍历队列
bool full_queue(QUEUE*); //判断是否为满
bool out_queue(QUEUE*, int*); //出队
bool emput_queue(QUEUE*); //判断是否位空
创建一个队列
void init(QUEUE* pQ) { pQ->pBase = (int*)malloc(sizeof(int) * l_queue); pQ->front = 0; pQ->rear = 0; }
判断为空 当队列删除元素到head=rear的时候,我们认为队列空了。pQ->front == pQ->rear
判读为满 当队列添加元素到rear的下一个元素是head的时候,也就是转圈子要碰头了,我们就认为队列满了。pQ->rear + 1) % l_queue == pQ->front
判断 空满
bool full_queue(QUEUE* pQ) { if ((pQ->rear + 1) % l_queue == pQ->front) return true; else return false; } bool emput_queue(QUEUE* pQ) { if (pQ->front == pQ->rear) return true; else return false; }
遍历队列
void traverse_queue(QUEUE* pQ) { int i = pQ->front; while (i != pQ->rear) { printf("%d ", pQ->pBase[i]); i = (i + 1) % l_queue; } printf("\n"); return; }
入队
bool in_queue(QUEUE* pQ, int val) { if (full_queue(pQ)) { return false; } else { pQ->pBase[pQ->rear] = val; pQ->rear = (pQ->rear + 1) % l_queue; return true; } }
出队
循环队列申请了一部分固定内存,内存即不出去,也也不进来,无需free();
bool out_queue(QUEUE* pQ, int* pVal) { if (emput_queue(pQ)) { return false; } else { pQ->front = (pQ->front + 1) % l_queue; return true; } }

浙公网安备 33010602011771号