实验内容:火车车厢重排问题。
实验说明:
转轨站示意图如下:
火车车厢重排算法伪代码如下:
1. 分别对k个队列初始化;
2. 初始化下一个要输出的车厢编号nowOut = 1;
3. 依次取入轨中的每一个车厢的编号;
3.1 如果入轨中的车厢编号等于nowOut,则
3.1.1 输出该车厢;
3.1.2 nowOut++;
3.2 否则,考察每一个缓冲轨队列
for (j=1; j<=k; j++)
3.2.1 取队列 j 的队头元素c;
3.2.2 如果c=nowOut,则
3.2.2.1 将队列 j 的队头元素出队并输出;
3.2.2.2 nowOut++;
3.3 如果入轨和缓冲轨的队头元素没有编号为nowOut的车厢,则
3.3.1 求小于入轨中第一个车厢编号的最大队尾元素所在队列编号j;
3.3.2 如果 j 存在,则把入轨中的第一个车厢移至缓冲轨 j;
实验过程
-
队列的基本算法实现
其中包含一些要实现火车车厢排列问题的必要基本算法实现,这几种算法的时间复杂度均为O(1)。
- #include<stdio.h>
- using namespace std;
- #define MaxSize 100
- typedef int ElemType;
- typedef struct SqQueue{
- ElemType data[MaxSize];//存放队中的元素
- int front, rear;//队头和队尾指针
- }SqQueue;//顺序队类型
- void InitQueue(SqQueue*& q) {//初始化队列
- q = new SqQueue;
- q->front = q->rear =-1;
- }
- bool EnQueue(SqQueue*& q, ElemType e) {//进队列
- if (q->rear == MaxSize - 1)//堆满上溢出
- return 0;
- q->data[q->rear] = e;
- q->rear++;
- return 1;
- }
- bool DeQueue(SqQueue*&q, ElemType& e) {//出队列
- if (q->front == q->rear)//堆满下溢出
- return 0;
- e = q->data[q->front];
- q->front++;
- return 1;
- }
- bool GetFront(SqQueue* q, ElemType& num) {//获取队头元素
- if (q->front == q->rear)
- return false;
- num = q->data[q->front];
- return true;
- }
- bool GetRear(SqQueue* q, ElemType& num) {//获取队尾元素
- if (q->front == q->rear)
- return false;
- num = q->data[q->rear-1];
- return true;
- }
-
重排和主函数
就算火车车厢的顺序打乱了之后,其编号也是连续的,可以利用这个点,所以我们定义三个队列:H1、H2、H3,将打乱的序列入队进H3,同时定义一个nowOut=1,让其自增,遍历序列H3,如当前遍历元素等于nowOut,那就将该元素出队,nowOut自增,否则就去H1和H2队列的对头去找有无等于nowOut的元素,若H1、H2、H3都没有nowOut,那么就将当前遍历的元素放进H1或H2条件是该元素必须大于H1或H2的队尾元素,如此循环完毕,最终可输出排列好的序列。
算法的时间复杂度均为O(nlog2n),n为火车车厢的长度。
- int main() {
- SqQueue* h1, * h2, * h3;//创建队列,相当于三条铁轨
- InitQueue(h1);
- InitQueue(h2);
- InitQueue(h3);
- SqQueue* Array[] = { h1,h2,h3 };//指向结构体的指针数组
- cout << "输入车厢号,输入0停止" << endl;
- while (1) {//先将元素入队h3
- int n;
- cin >> n;
- if (n == 0)
- break;
- EnQueue(h3, n);
- }
- int nowOut = 1;//下一个输出的车厢编号,最开始为1
- cout << "排序后" << endl;
- while (h1->front < h1->rear || h2->front < h2->rear || h3->front < h3->rear) {
- //所有队列全为空时,退出循环
- int flag = 0;//为0时,表示入轨和缓冲轨对头都没有编号为nowOut的车厢
- //为1,表示在入轨和缓冲轨队头找到编号为nowOut的车厢
- int num;
- GetFront(h3,num);//获取入轨的队头元素
- if (num == nowOut) {//与nowOut一样时,直接出队列
- DeQueue(h3, num);
- nowOut++;
- cout << num<<" ";
- flag = 1;
- }
- else {
- for (int i = 0; i < 2; i++) {//在缓冲队列中找
- GetFront(Array[i], num);
- if (num == nowOut) {
- DeQueue(Array[i], num);
- nowOut++;
- cout << num<<" ";
- flag = 1;
- }
- }
- }
- if (flag == 0) {//入轨和缓冲轨中都没有
- int a;
- for (int i = 0; i < 2; i++) {//求小于入轨中第一个车厢编号的最大队尾元素所在队列编号
- GetFront(h3, num);
- GetRear(Array[i], a);
- if (num > a || Array[i]->rear == -1) {
- //如果存在,则把入轨中的第一个车厢移至缓冲轨
- DeQueue(h3, num);
- EnQueue(Array[i], num);
- break;
- }
- else if(i==1){//轨道数量太少,没有解决的办法
- cout << "没有解决的办法" << endl;
- return 0;
- }
- }
- }
- }
- return 0;
- }
执行结果
总结
队列相当于一种操作限制的线性表,只能在一端进行插入操作,另一端进行删除操作,被称为先进先出表。队列通常作为一种存放临时变量的容器,如果先存入的元素先处理,就可采用队列。该算法中用到的队列是线性存储结构,只要在出队入队操作中稍加修改,就会变成环形队列。当火车车厢是任意打乱顺序的排列,两条缓冲轨是无法解决整个问题的,需要多添加几个轨道,也就是多定义队列来解决这个问题