车厢重排过程详解,c++实现
对应《数据结构,算法与应用》p190,书上写得太笼统了,因此自己写了很多注释,以便于日后查看,温故知新。
下面展示一些 算法代码
。
// An highlighted block
/*本程序主要模拟车厢重排过程,有以下说明:
1.重拍过程在转轨站进行
2.转轨站有一个入口和一个出口,并有多个缓冲区
3.一个缓冲区可以放多节车厢
4.每节车厢可以直接从入到出或者塞入任意缓冲区
5.缓冲区车厢不能回到入站口,只能去出站口
6.重排不一定成功
*/
#include<stack>
#include<vector>
#include<iostream>
using namespace std;
stack<int> *track; //缓冲轨道数组
vector<int>resortedCars;//排好序的数组
int numOfCars; //传入的数组长度
int numOfTracks; //缓冲轨道数量
int smallestCar; //在缓冲轨道中编号最小的车厢
int itsTrack; //停靠最小编号车厢的缓冲轨道
void outputFromHoldingTrack();
bool putInHoldingTrack(int);
template<class T>
int length(T& data)
{
return sizeof(data) / sizeof(data[0]);
}
bool railRoad(int input[], int thenumOfTracks)
{
numOfTracks = thenumOfTracks; //轨道数目
//用于创建用于缓冲的轨道栈
track = new stack<int>[numOfTracks + 1];//0没用
int nextCarToOutput = 1;
smallestCar = numOfCars+2; //防止指针越界,原文是直接长度加1,但是如果之前车就是排好的,就会报错;
//这样一在缓冲区的情况下,smallestcar不会被更新,就不可能有车从缓冲区出去;
//重排车厢
for (int i = 1; i <= numOfCars; i++)
{
if (input[i-1] == nextCarToOutput)//如果遍历一遍,把里面从1开始顺序增加的都单独拎出来,放入出轨
{
cout << "直接把" << input[i - 1] << "车厢移至出轨" << endl;
resortedCars.push_back(input[i-1]);
nextCarToOutput++;
if (nextCarToOutput == numOfCars + 1 && smallestCar == numOfCars + 2)//如果不需要放入缓冲区就已经排好了,那么返回真
{
return true;
}
while (smallestCar == nextCarToOutput)//如果栈区有符合条件的车,直接放入出轨,
//如果放出去一个之后还有满足要求的,继续放,直到没有为止
{
outputFromHoldingTrack();
nextCarToOutput++;
}
}
else//无法直接拎出来的放入缓冲区
{
if (!putInHoldingTrack(input[i-1]))//如果返回错误则无法放入缓冲区,无法排序
{
return false;
}
}
}
return true;
}
void outputFromHoldingTrack()
{
//将编号最小的车厢从缓冲轨道移到出轨
resortedCars.push_back(track[itsTrack].top());
track[itsTrack].pop();
cout << "将" << smallestCar << "从缓冲区" << itsTrack << "移到出轨" << endl;
//检查所有栈,在栈顶查找编号最小的车厢与其所属的栈编号,
//因为放了车出去,需要更新最小车的编号以及对应的缓冲区序号
smallestCar = numOfCars + 2;//人为规定一个极大值,所有的栈顶元素都比它小
for (int i = 1; i <= numOfTracks; i++)
{
if (!track[i].empty() && (track[i].top() < smallestCar))
{
smallestCar = track[i].top();
itsTrack = i;
}
}
}
bool putInHoldingTrack(int c)
{
int bestTrack = 0;
int besttop = numOfCars + 2;//取besttrack中顶部的车厢
//同样是人为规定一个极大值
for (int i = 1; i < numOfTracks+1; i++)//对于每一个缓冲区进行如下操作
{
if (!track[i].empty())
{
int topcar = track[i].top();//取出栈顶元素
if (c < topcar&&topcar < besttop)
//如果传入的元素比某一个栈的栈顶元素小
//并且栈顶元素比人为规定的最大值还要小
{
besttop = topcar;//那么栈顶元素替代人为规定的最大值
//这一步是希望找出大于c的栈顶元素及其所在的栈
bestTrack = i;
}
}
else//缓冲轨道空了,但是不一定是这个值
{
if (bestTrack == 0)//但是如果前面后面都没有合适的值,才会放在这里,这个if用得很巧妙
{
bestTrack = i;
//如果第一个是空的,后面不是空的并且满足条件,那么会放在后面,这样自然没问题
//如果前面得到了besttrack值,那么即使是空的也不放在这里,尽量能省就省
}
}
}
if (bestTrack == 0)
{
return false;//经过上述循环找不到可以用的缓冲轨道
}
else
{
track[bestTrack].push(c);
cout << "将" << c << "从入轨移到" << bestTrack << "号缓冲区" << endl;
if (c < smallestCar) //上述循环只是找到了目标栈并且放入了车
//但是最小的车及其缓冲区序号还没更新
//如果传入的编号比人为规定的小,那么更新
//这一步目的是确保smallestCar是缓冲区中最小的车
{
smallestCar = c;
itsTrack = bestTrack;
}
return true;
}
}
代码使用过程:
下面展示一些 代码使用
。
// An highlighted block
void main()
{
int cars[9] = {3,6,9,2,4,7,1,8,5};
numOfCars = length(cars);//获取存入车辆的数量,不能对形参使用,否则
if (railRoad(cars, 3))
{
cout << resortedCars.size() << endl;
for (auto i : resortedCars)
{
cout << i << "\t";
}
cout << endl;
}
else
{
cout << "unable to sort" << endl;
}
delete[] track;
system("pause");
}
结果:
下面介绍另一种方式,借助队列进行列车重排
下面展示一些 利用队列完成
。
// 定义全局变量并且在函数中分配空间
//记得释放内存
queue<int> *track2;
track2 = new queue<int>[numOfTracks + 1];
// 将主函数中更改对应调用函数即可
oid outputFromHoldingTrack2()
{
//将编号最小的车厢从缓冲轨道移到出轨
resortedCars.push_back(track2[itsTrack].front());
track2[itsTrack].pop();
cout << "将" << smallestCar << "从缓冲区" << itsTrack << "移到出轨" << endl;
smallestCar = numOfCars + 2;
for (int i = 1; i <= numOfTracks; i++)
{
if (!track2[i].empty() && track2[i].front() < smallestCar)
{
smallestCar = track2[i].front();
itsTrack = i;
}
}
}
bool putInHoldingTrack2(int c)
{
int bestTrack = 0;
int bestlast = 0;
for (int i = 1; i < numOfTracks + 1; i++)
{
if (!track2[i].empty())
{
int lastCar = track2[i].back();
if (c > lastCar&&lastCar>bestlast)
{
bestlast = lastCar;
bestTrack = i;
}
}
else
{
if (bestTrack == 0)
{
bestTrack = i;
}
}
}
if (bestTrack == 0)
{
return false;
}
track2[bestTrack].push(c);
cout << "将" << c << "从入轨移到" << bestTrack << "号缓冲区" << endl;
if (c < smallestCar)
{
smallestCar = c;
itsTrack = bestTrack;
}
return true;
}