赞
踩
队列是日常生活中最常见的,例如,到食堂买饭要排队,去银行要排队,到车站买票要排队,操作系统的进程需要排队等等。和栈相似,队列也是一种操作受限制的线性结构,我们限制在一端插入(称为:入队),在另一端删除(称为:出队),先进入队的成员总是先离开队列;因此,,队列也称做先进先出的线性表。
(1).队列:是一种特殊的线性表,只允许在表的一端进行插人 ,而在另一端进行删除
(2).队首:允许进行删除的一端称为队首,用队首指针front表示。
(3).队尾:允许进行插人的-端称为队尾.用队尾指针rear表示。
说明:队列中没有元素时称为空队列。在空队列中依次加人元素a1,a2,…,an,之后.a1是队首元素,an是队尾元素。人队只能在队尾插人,出队的次序也只能是a1,a2,a3,…,an,即队列的修改是依次的先进先出的原则进行的。
顺序队列,采用顺序存储结构存储的队列简称为顺序队列,顺序队列也采用数组来实现,要设定两个整数变量才指示队头和队尾的位置,称为队头指针front 和队尾指针 rear ,顺序队列的类型定义如下:
//创建队列顺序队列的自定义类型
#define maxsize 100
typedef int Elemtype;
typedef struct Snode
{
Elemtype data[maxsize];
int front, rear; //队头指针,队尾指针
}SqQueue;
说明:
(1).设置Q是指向定义好的顺序队列的指针,初始Q->rear = Q->front =0;
(2).入队操作时因为初始队首和队尾都是0号的位置,这时,将元素插入在队尾的位置后,Q->rear再加1,所以顺序队列中的队尾指针rear指向队尾元素的下一个位置。出队操作时,需先将队列首元素取出,然后Q->front加1;
(3).Q->data[Q->front]存放队首元素的值,Q->data[Q->rear-1],存放队尾元素的值。
(4).队列空的条件是Q->rear 等于 Q->front ,队列满的条件是Q->rear等于QUEUESIZE(队列最大值)
1.假溢出现象
初始化队列Q时,Q->rear==Q- > front=0;入队时,新元素存入队尾指针所指向的单元,队尾指针再往后移动一个;出队运算时 ,取出队首所指向指针所指向单元的元素的值。队首指针再往后移动一个。 也就是说,在非空顺序队列中 .队头指针始终指向当前的队头元素,而队尾指针始终指向队尾元素的下一个单元。
随着人队和出队的不断进行,整个队列不断后移,当Q ->rear== QUEUESIZE时,尾指针无法再移动则表示队满,但却不是真正的队满,因为经过出队操作后,队列前面出现了一些空单元。由于入队只能在队尾进行,队首之前的空存储单元无法使用,我们把这种现象称为“假溢出”,即存储空间未满,可是不能再做入队运算。
解决“假溢出”问题可以有两种方法:
(1)平移元素:把元素平移到队列的首部,但这种方法效率低。
(2)将新元素插人到第一个位置 上,构成循环队列,人队 和出队仍按“先进先出”的原则进行。但这种方法操作效率、空间利用率高。
因此,为了解决“假溢出”问题,我们一般采用循环队列的方法。即把顺序队列想象成一个首尾相接环状结构,即规定最后.个单元的后继为第一一个单元,并称这种环状数组表示的队列为循环队列。采用循环队列存储的队列,当尾指针指向队尾单元时,插入一个元素后 ,尾指针加1不再是指向队列存储空间之外,而是让尾指针指向第一个存储单元是空的,可以继续插入新元素。循环队列的结构体定义与顺序队列一致。将队列的存储空间构造成首尾相接的环状结构,存储在这样结构的队列称为循环队列(Cireular Queue)。在循环队列中进行出队、人队操作时,头尾指针仍要加1.向后移动。只不过当头尾指针指向上界(QUEUESIZE 1)时,其加1操作的结果是应当指向的下界0。
为了有效地区分队列满还是空,我们有多种方法可以采取,比较典型的有如下三种:
(1)多设一个逻辑变量存放队列满还是空。
(2)多使用一个整型变量做计数器来记录队列中元素的总数(即队列长度)。若相等则认为队满(注意:rear所指的单元始终为空)。
(3)少用一个元素的空间,约定人队前,测试尾指针在循环意义下加1后是否等于头指针,若相等则认为队满(注意:rear所指的单元始终为空)。
为了解决这一问题我们在本教材里采用第三种方法,即规定循环队列中始终留一个空的元素空间,即尾指针rear 所指向的空间永远是没有元素的。我们称这种方法为“队尾加1追上队首即为队列满”。
基本运算包括:队列的初始化,判队空,判队满,入队,出队等操作;
下面,附代码参考:
在这里插入代码片: #include <iostream> #include <stdlib.h> using namespace std; //创建队列顺序队列的自定义类型 #define maxsize 100 typedef int Elemtype; typedef struct Snode { Elemtype data[maxsize]; int front, rear; //队头指针,队尾指针 }SqQueue; SqQueue* InitSqQueue() //初始化队列 { SqQueue* Q; Q = (SqQueue*)malloc(sizeof(SqQueue)); //给队列申请空间 if (!Q) { return 0; } else { Q->front = Q->rear = 0; //初始队首与队尾指针都指向0 return Q; } } void AssignQueue(SqQueue* Q) //顺序栈的输入 { int i, lenghth; cout << "请输入顺序栈的长度" << endl; //输入栈的长度 cin >> lenghth; cout << "请根据设定的长依次输入顺序栈的元素(用空格隔开)" << endl; for (int i = 0; i < lenghth; i++) { cin >> Q->data[i]; //输入栈的元素 Q->rear = (Q->rear+1)%maxsize; //栈顶不断向后移动 } } //循环队列的入队操作 //算法思路 //1.判断队列是否已满,若已经满了,给出溢出提示,若没有,则进行下一步 //2.将新元素赋值给队尾元素位置 //3.队尾指针加1 int EnQueue(SqQueue* Q, Elemtype x) { if ((Q->rear + 1) % maxsize == Q->front) //判断队列是否已满 { cout << "队列已经满了" << endl; return 0; } else { Q->data[Q->rear] = x; //将新的值赋值给队列的队尾 Q->rear = (Q->rear + 1) % maxsize; //循环队列的队尾始终指向队尾的下一个空间 return 1; } } //循环队列的出队运算 //删除循环队列的队首元素,并通过指针变量将队首元素的值带出,即出队运算 //1.判断是否队空,对空则无元素出队,给出提示返回信息,若是非空队列的值出队,接下来下一步 //2.将队首元素的值赋值给指针变量所指的存储空间 //3.队首值加1; int DeleQueue(SqQueue* Q, Elemtype* x) { if (Q->rear == Q->front) //判断是否队空,对空则无元素出队 { return 0; } else { *x = Q->data[Q->front]; //将队首释放 Q->front = (Q->front + 1) % maxsize; //队首位置向后移动 return 1; } } //顺序栈的输出显示 void OputSqlist(SqQueue* Q) { int i; int sum = Q->rear; int toal = Q->front; cout << "顺序表长度为:" << sum - toal << endl; cout << "依次输出顺序表的元素:" << endl; for (i = toal; i < sum ; i++) { cout << Q->data[i] << ' '; //遍历顺序表,并打印在控制台上 } } int main() { SqQueue* Q = InitSqQueue(); //创建循环队列 Elemtype k, u; if (Q == 0) { cout << "初始化失败" << endl; } else { cout << "初始化成功" << endl; AssignQueue(Q); OputSqlist(Q); cout << endl; cout << "请输入需要入队的值:" << endl; cin >> k; EnQueue(Q,k); OputSqlist(Q); cout << endl; cout << "出队显示为:" << endl; DeleQueue(Q, &u); OputSqlist(Q); } return 0; }
队列不仅可以采用顺序的存储结构,也可以采用链表的存储结构,称为链队列;与链表类似,通常为了操作方便会比我们前面链表的程序多设置一个头节点,并设置一个队头指针和一个队尾指针,但与链表的不同之处在于,链队列的插入在队尾进行,删除操作在对头进行。
链队列的基本运算包括初始化,判空,入队,出队;
下面附代码,方便理解:
#include<iostream> #include <stdlib.h> using namespace std; typedef int Elemtype; //结点定义 typedef struct Qnode { Elemtype data; struct Qnode* next; }Qnode; //链队列定义 typedef struct { Qnode* front; //设置队头指针 Qnode* rear; //设置队尾指针 int length; //计算队的长度 }QLinklist; int InitQueue(QLinklist* Q) //队列初始话 { Q->front = Q->rear = (Qnode*)malloc(sizeof(Qnode)); //将两个指针申请空间 if (!Q->front) { return 0; } else { Q->front->next = NULL; //让队头指针下一个元素空间指向空 Q->length = 0; return 1; } } int QueueEmpty(QLinklist* Q) { if (Q->front == Q->rear) //判断队头指针于队尾指针是否为空 { return 1; } else { return 0; } } int EnQueue(QLinklist* Q, Elemtype e) { Qnode* p; p = (Qnode*)malloc(sizeof(Qnode)); //设置一个插入指针 if (!p) { return 0; } else { p->data = e; //取得需要插入的新值 p->next = NULL; //指针指向的值一定是从队尾插入的 Q->rear->next = p; Q->rear = p; //赋值给队尾,这样队尾就是空的的了 Q->length++; return 1; } } int DeQueue(QLinklist* Q, Elemtype* e) { Qnode* p; if (QueueEmpty(Q)) //先判断队列是否为空 { return 0; } p = Q->front->next; //先让头结点指向下一个有数据的值(即首元素结点) *e = p->data; //再将这个首元素结点用中间变量替换 Q->front->next = p->next; //最后让首元素结点的下一个指针,作为头节点的下一个首元素结点 //如果删除的结点是尾结点,将队尾结点指针指向头节点 if (p == Q->rear) { Q->rear = Q->front; } free(p); Q->length--; return 1; } void OutputQueue(QLinklist* Q) { Qnode* p; int i; p = Q->front->next; //从头节点的首元素开始打印,毕竟,先进先出 while (p != NULL) { cout << p->data << " "; p = p->next; } } int main() { QLinklist* Q = (QLinklist*)malloc(sizeof(QLinklist)); Elemtype k, e; k = InitQueue(Q); if (k == 0) { cout << "初始化失败" << endl; } else { cout << "初始化成功" << endl; EnQueue(Q, 5); //将52022依次入队 EnQueue(Q, 2); EnQueue(Q, 0); EnQueue(Q, 2); EnQueue(Q, 2); cout << "入队显示:" << endl; OutputQueue(Q); cout << endl; cout << "出队显示:" << endl; DeQueue(Q, &e); OutputQueue(Q); } return 0; }
“回文”是指正读和反读均相同的字符串;例如,ababa是“回文”字符串。试设计一个算法,利用顺序栈和循环队列的基本运算,判断一个字符串是否是回文。
分析:所谓“回文”,是指正读和反读均相同的字符串。 顺序栈的特点是“先进后出”,即,出栈是逆序;而循环队列的特点是“先进先出”,即出队是顺序。所以只要先将字符串依次入栈、入队,然后依次将出栈的字符和出队的字符进行比较,如果完全一致即是回文;否则不是回文。
代码参考:
#include <iostream> #include <stdlib.h> using namespace std; //创建队列顺序队列的自定义类型 #define maxsize 100 typedef int Elemtype; typedef struct Snode { Elemtype data[maxsize]; int front, rear; //队头指针,队尾指针 }SqQueue; SqQueue* InitSqQueue() //初始化队列 { SqQueue* Q; Q = (SqQueue*)malloc(sizeof(SqQueue)); //给队列申请空间 if (!Q) { return 0; } else { Q->front = Q->rear = 0; //初始队首与队尾指针都指向0 return Q; } } typedef struct { Elemtype date[maxsize]; int top; //top栈顶元素,top实际并不是指针类型,存放的是栈顶元素的下标 }SqStack; SqStack* InitSqStack() //顺序栈的初始化 { SqStack* s; s = (SqStack*)malloc(sizeof(SqStack)); //申请顺序栈的空间 if (!s) { return NULL; //申请失败返回0 } else { s->top = -1; //申请成功设置为空栈,这样初始化成功 return s; } } //顺序栈的插入 //将一个新的元素加入栈中,通常称为入栈和压栈 //算法思路: //1.判断栈是否满,如果栈满了,给出提示,出错返回 //2.栈顶加1 //3.新元素赋值给栈顶 //4.完成返回 int Push(SqStack* s, Elemtype x) { if (s->top == maxsize - 1) //判断栈是否满了 { //可以改改define的值,这样看看程序会不会出错 return 0; } else { s->top++; //栈顶加1 s->date[s->top] = x; //将新元素的值赋值新栈顶 return 1; } } //顺序栈的删除(出栈) //将栈顶的元素删除 //算法思路: //1.判断栈是否为空,若是空栈,则没有元素出栈,给出提示出错返回 //2.将栈顶元素赋值给x指针所指向的变量 //3.栈顶指针减1 //4.完成返回 int delepop(SqStack* s, Elemtype* u) { if (s->top == -1) { cout << "此栈为空栈" << endl; //判断是否为空栈(插入的就判断是否已经满了,删除判断是否为空) return 0; } else { *u = s->date[s->top]; //将栈的元素赋值给一个新元素指针存着,之后在栈顶减一 s->top--; //其实这个函数还是在这个数组中,但它不在这个栈中,如果你加回来,在输出,还是能看到原来的数 return 1; } } //循环队列的入队操作 //算法思路 //1.判断队列是否已满,若已经满了,给出溢出提示,若没有,则进行下一步 //2.将新元素赋值给队尾元素位置 //3.队尾指针加1 int EnQueue(SqQueue* Q, Elemtype x) { if ((Q->rear + 1) % maxsize == Q->front) //判断队列是否已满 { cout << "队列已经满了" << endl; return 0; } else { Q->data[Q->rear] = x; //将新的值赋值给队列的队尾 Q->rear = (Q->rear + 1) % maxsize; //循环队列的队尾始终指向队尾的下一个空间 return 1; } } //循环队列的出队运算 //删除循环队列的队首元素,并通过指针变量将队首元素的值带出,即出队运算 //1.判断是否队空,对空则无元素出队,给出提示返回信息,若是非空队列的值出队,接下来下一步 //2.将队首元素的值赋值给指针变量所指的存储空间 //3.队首值加1; int DeleQueue(SqQueue *Q, Elemtype *x) { if (Q->rear == Q->front) //判断是否队空,对空则无元素出队 { return 0; } else { *x = Q->data[Q->front]; //将队首释放 Q->front = (Q->front + 1) % maxsize; //队首位置向后移动 return 1; } } int main() { SqQueue* Q = InitSqQueue(); //创建循环队列 SqStack* S = InitSqStack(); //创建顺序栈 Elemtype ch, x,y; if (S == 0 || Q == 0) { cout << "初始化失败" << endl; } else { cout << "请依次输入字符" << endl; ch = getchar(); while (ch != '\n') { Push(S, ch); //字符串入栈 EnQueue(Q, ch); //字符串入队 ch = getchar(); } while (S->top != -1) { delepop(S, &x); DeleQueue(Q, &y); if (x != y) { cout << "输入的不是回文数" << endl; break; } } if (S->top == -1) { cout << "输入的字符串是回文数" << endl; } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。