1.队列简介
队列:FIFO (先入先出) ----》 头 head 尾 tail
队列存储结构的实现有以下两种方式:
两者的区别仅是顺序表和链表的区别,即在实际的物理空间中,数据集中存储的队列是顺序队列,分散存储的队列是链队列。
实际生活中,队列的应用随处可见,比如排队买 XXX、医院的挂号系统等,采用的都是队列的结构。
拿排队买票来说,所有的人排成一队,先到者排的就靠前,后到者只能从队尾排队等待,队中的每个人都必须等到自己前面的所有人全部买票成功并从队头出队后,才轮到自己买票。这就是典型的队列结构
2.假溢出---->循环队列
顺序队列整体后移造成的影响是:
- 顺序队列之前的数组存储空间将无法再被使用,造成了空间浪费;
- 如果顺序表申请的空间不足够大,则直接造成程序中数组 a 溢出,产生溢出错误;
使用此方法需要注意的是,顺序队列在判断数组是否已满时,出现下面情况:
(1)当队列为空时,队列的头指针等于队列的尾指针
(2)当数组满员时,队列的尾指针+1 =队列的头指针,说明马上要满
重点:如何判断队列为满 ---》一个不大于MAX的数与MAX取余运算,结果仍然是该数本身
# include <stdio.h>
# define SIZE 512
char queue[SIZE];
int head = 0, tail = 0;
//函数声明
int is_empty(void);
int is_full(void);
void enqueue(char c);
char dequeue(void);
// 主函数
int main(void)
{
char c = 'A';
int i;
for(i = 0; i < 3; i++) // 依次入队列 A B C
{
if(!is_full()) // 入队列之前先判断是否为满
{
enqueue(c); // 入队
c++;
}
}
while(!is_empty()) // 出队列先判断是否为空
{
putchar(dequeue()); // 不为空则输出
}
printf("\n");
return 0;
}
//循环队列入队
void enqueue(char c)
{
queue[tail] = c;
tail = (tail+1) % SIZE;
}
//出队
char dequeue(void)
{
char ch;
ch = queue[head];
head = (head + 1) % SIZE;
return ch;
}
//判断队列是否为空
int is_empty(void)
{
return head == tail;
}
//判断队列为满
int is_full(void)
{
return (tail + 1) % SIZE == head;
}
//输出ABC
3. 队列应用
1.已知一个数列组合是经过加密后的一串数字,那么现在知道这串加密后的数字,并且知道如何破解的方法,求加密前数字的组合是什么。
破解的方法:首先将第1个数删除,紧接着将第2个数放到这串数的末尾,再将第3个数删除并将第4个数放到这串数的未尾,再将第5个数删除---直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些删除的数连在起就是原始的数据。
#include <stdio.h>
#include <string.h>
#define SIZE 512
char queue[SIZE];
int head = 0, tail = 0;
//函数声明
int is_empty(void);
int is_full(void);
void enqueue(char c);
char dequeue(void);
//主函数
int main(void)
{
char code[10];
int n;
int i = 0;
char num;
printf("pleade enter a code:");
gets(code);
for(n = 0; n < strlen(code); n++)
{
if(!is_full()) //判断是否为满
enqueue(code[n]);
}
while(!is_empty())
{
code[i++] = dequeue();
if(!is_empty()) // 出队列之前判断是否为空
{
num = dequeue(); // 出队列
// if(!is_full()) // 入队列之前判断是否为满
///{
enqueue(num);
//}
}
}
printf("origin code is:");
for(i = 0; i < strlen(code); i++)
{
printf("%c", code[i]);
}
printf("\n");
return 0;
}
//循环队列入队
void enqueue(char c)
{
queue[tail] = c;
tail = (tail+1) % SIZE;
}
//出队
char dequeue(void)
{
char ch;
ch = queue[head];
head = (head + 1) % SIZE;
return ch;
}
//判断队列是否为空
int is_empty(void)
{
return head == tail;
}
//判断队列为满
int is_full(void)
{
return (tail + 1) % SIZE == head;
}
4.双端队列
双端队列又名double ended queue
,简称deque,双端队列没有队列和栈这样的限制级,它允许两端进行入队和出队操作,也就是说元素可以从队头出队和入队,也可以从队尾出队和入队。
循环队列:(1.入队列(tail端入队列) 2.出队列(head端出队列) 3.队列是否为满 4.队列是否为空)
双端循环队列:1.head端出入队列 2.tail端出入队列 3.队列是否为满 4.队列是否为空
使用双端队列解决回文问题
#include <stdio.h>
#include <string.h>
#define SIZE 512
char queue[SIZE];
int head = 0, tail = 0;
//函数声明
int is_empty(void);
int is_full(void);
void tail_enqueue(char c);
char tail_dequeue(void);
void head_enqueue(char c);
char head_dequeue(void);
int is_palindrom(char *pt);
//主函数
int main(void)
{
char str[100];
printf("please enter a string:");
gets(str);
//回文判定
if(is_palindrom(str))
printf("str is a palindrom\n");
else
printf("str is not a palindrom\n");
printf("\n");
return 0;
}
//tail端入队列
void tail_enqueue(char c)
{
queue[tail] = c;
tail = (tail+1) % SIZE;
}
//tail端出队列
char tail_dequeue(void)
{
tail = (tail - 1 + SIZE) % SIZE;
return queue[tail];
}
//head端入队列
void head_enqueue(char c)
{
head = (head - 1 + SIZE) % SIZE;
queue[head] = c;
}
//head端出队列
char head_dequeue(void)
{
char ch;
ch = queue[head];
head = (head + 1) % SIZE;
return ch;
}
//判断队列是否为空
int is_empty(void)
{
return head == tail;
}
//判断队列为满
int is_full(void)
{
return (tail + 1) % SIZE == head;
}
//判断回文函数
int is_palindrom(char *pt)
{
int i, len;
len = strlen(pt);
char c1, c2;
for(i = 0; i < len; i++)
{
if(!is_full())
tail_enqueue(pt[i]);
}
while(!is_empty())
{
c1 = head_dequeue();
if(!is_empty())
c2 = tail_dequeue();
else
break;
if(c1 == c2)
continue;
else
return 0;
}
return 1;
}