车厢重排过程基于栈或队列详解,c++实现

车厢重排过程详解,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;
}
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无情の学习机器

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值