深入理解数据结构——列车重排算法

#include <iostream>
#include <string>

using namespace std;

typedef int EType;     // 自定义链表的数据元素为整数。

struct QType {
	int number;
};
//定义队列顺序存储结构
struct Queue
{
	QType* element;          // 存放结点的数据元素。
	int front;				//对头节点
	int rear;				//队尾节点
	int maxsize;			//队列最大容量
};

//构造空队列算法
void CreatQueue(Queue& Q, int MaxQueueSize) {
	Q.maxsize = MaxQueueSize;
	Q.element = new QType[Q.maxsize];
	Q.front = 0;
	Q.rear = 0;
}

//判断队列是否为空
bool IsEmpty(Queue& Q) {
	if (Q.front == Q.rear) return true;
	return false;
}

//判断队列是否满了front=rear+1;
bool IsFull(Queue& Q) {
	if (Q.front == (Q.rear + 1) % (Q.maxsize + 1)) return true;
	return false;
}

//返回队头元素的值
bool GetFront(Queue& Q, QType& result) {
	//将font后面一个位置的队列元素的值取出
	if (IsEmpty(Q)) return false;
	result = Q.element[(Q.front + 1) % (Q.maxsize + 1)];
	return true;
}

//返回队尾元素的值
bool GetRear(Queue& Q, QType& result) {
	//将font后面一个位置的队列元素的值取出
	if (IsEmpty(Q)) return false;
	result = Q.element[(Q.rear + 1) % (Q.maxsize + 1)];
	return true;
}


//进队运算
//将一个新的的元素x存储到当前rear所指空间的下一个位置,首先要判断队列是否为满了
bool EnQueue(Queue& Q, QType& x) {
	if (IsFull(Q)) return false;
	Q.rear = (Q.rear ) % (Q.maxsize + 1); //rear指向空间
	Q.element[Q.rear] = x;//存入x
	return true;
}

//出队运算
//将front所指空间的下一个位置的元素取出,首先要判断队列是否为空
bool OutQueue(Queue& Q, QType& result) {
	if (IsEmpty(Q)) return false;
	Q.front = (Q.front + 1) % (Q.maxsize + 1); //front指向空间的下一个位置
	result = Q.element[Q.front];
	return true;
}


/*
开始时,n节车厢进入缓冲轨道,再从缓冲轨道按编号1至编号n的次序离开缓冲轨道,进入出轨

为了重排车厢,需要按车厢到达入轨的先后,从前至后依次检查如果上的所有车厢。
如果正在检车的车厢就是下一个满足排列要求的车厢,就可以直接把它放到出轨上去。

如果不是,则把他移动到缓冲轨道上,再按输出次序要求,轮到它时才将它放到出轨上
缓冲铁轨是按照FIFO队列的方式使用的。

RearrangementTrack重新排列n个车厢,它最多可以使用k个缓冲轨道,如果缓冲轨道不足,不能成功地重排
则返回false,否则返回true

开始创建一个指向k个队列的表头数组Q[k],其中Q[i](i=1,2,...k)表示第i个缓冲轨道。NowOut是下一个要输出至出轨
的车厢号。minH是已经进入到各缓冲轨道中最小的车厢号,minQ是minH所在是缓冲铁轨,即队列编号

算法OutPut用于将当前再缓冲轨道中可以送到出轨的车厢,送至出轨,它同时再寻找缓冲轨道中最小的车厢编号的车厢
确认其能否送至出轨,如可以则送至出轨,并修改minQ和minH

算法Hold根据车厢调度规则,把某个暂时不能送至出轨的车厢current送人一个缓冲轨道,
如果current可以成为缓冲轨道中新的最小车厢,就修改minQ和minH。

将一节暂时不能送至出轨的车厢移动到缓冲铁轨是,采用如下的原则确定应该把这节车厢移动到哪一个缓冲铁轨,
这个原则可以减少缓冲铁轨的使用。
(1)该缓冲轨道上现有的各车厢的编号都小于current
(2)如果多个缓冲轨道都满足这一条件,则选择第一个缓冲轨道队尾(左端)车厢编号醉倒的缓冲铁轨
(3)如果已有车厢的缓冲铁轨中,队尾的车厢编号都大于current,则current选择一个空的缓冲铁轨(如果存在)则进入
(4)如果无空缓冲铁轨可选择,则无法调度
*/
bool RearrangementTrack(int r[],int n,int k) {
	//车厢初始排列为r[1:n],如果成功排列则返回true,否则false
	//创建k个缓冲铁轨队列H,并初始化为空队列

	Queue* Q = new Queue[k];
	int MaxQueueSize = 10;

	for (int i = 0; i < k; i++) {
		CreatQueue(Q[i], MaxQueueSize);
	}
	int NowOut = 1;//当前应该输出的车厢编号
	int minH = n + 1;//缓冲轨道中编号最小的车厢编号,目前假设为0_____车厢编号
	int minQ;//minQ车厢对应的缓冲铁轨编号______铁轨编号

	for (int i = 1; i <= n; i++) {
		if (r[i] == NowOut) {
			//当前到站的车厢编号是刚刚出站的车厢编号的后一个,则直接输出
			cout << "从入轨输出" << r[i] << "号车厢到出轨" << endl;
			if (NowOut != n)//如果车厢还没有发完
				NowOut++;//当前应该输出下一车厢
			while (minH == NowOut) {//缓冲轨道中编号最小的车厢编号就是当前应该发车的车厢编号
				//从缓冲轨道输出minH
				OutPut(minH, minQ, Q, k, n);
				if (NowOut != n)
					NowOut++;//当前应该输出下一车厢
			}
		}
		else { //将r[i]送入某个缓冲轨道
			if (!Hold(r[i], minH, minQ, Q, k, n)) {
				delete []Q;
				return false;
			}
		}
		delete []Q;
		return true;

	}
}


void OutPut(int &minH,int &minQ,Queue Q[],int k,int n) {
		//	从minQ中输出最小车厢minH,寻找下一个最小的车厢编号minH及对应的铁轨编号
		
	int current;//当前的车厢编号
	QType x;
	x.number = minH;//当前最小车厢编号
	OutQueue(Q[minQ], x);//最小车厢轨道中弹出最小车厢
	cout << "从" << minQ << "号缓冲铁轨输出" << minH << "号车厢到出轨" << endl;
	minH = n + 1;//假设一个最小的车厢编号,它比实际的车厢号大,以后替换

	for (int i = 1; i < k;i++) {
		//通过检查所有队列的首部,寻找新的minQ和minH
		GetFront(Q[i], x);
		current = x.number;
		if (!IsEmpty(Q[i]) && current < minH) {//如果该轨道的车厢不为空,并且当前的车厢编号小于最小的车厢编号
			minH = current;//最小的车厢编号就是当前车厢编号
			minQ = i;//当前轨道就是最小车厢所在轨道
		}
	}
}

bool Hold(int current,int &minH,int &minQ,Queue Q[],int k,int n) {
	//为车厢current寻找最优的缓冲铁轨,如果没有,则返回false,否则返回true

	int BestCushion = 0;//目前最优的缓冲铁轨,为0时表示还未找到最优的缓冲铁轨
	int BestLast = 0;   //BestCushion最优的缓冲铁轨的最后一节车厢编号
	QType x;           //车厢的编号
	for (int i = 1; i < k; i++) {//扫描缓冲轨道
		if (!IsEmpty(Q[i])) {
			//缓冲轨道i不为空
			GetRear(Q[i], x);//缓冲轨道的最后一个车厢,返回给x
			if (current > x.number && x.number > BestLast) {
				//当前车厢大于x车厢,并且x车厢大于最优轨道的最后一节车厢
				BestLast = x.number;
				BestCushion = i;
			}
		}
		else {//current小于已使用缓冲轨道的最后一节车厢的编号,则进入未使用的缓冲轨道i
			if (!BestCushion) BestCushion = i;
		}
	}

	if (!BestCushion) {//无可用缓冲轨道,无法调度,失败
		cout << "wrong!!!缓冲轨道不足,无法调度,失败" << endl;
		return false;
	}
	x.number = current;
	EnQueue(Q[BestCushion], x);//吧current压入最有铁轨队列
	cout << "从入轨将" << current << "号车厢一道最优缓冲铁轨" << BestCushion << endl;
	if (current < minQ) {
		//检查current是否可以成为新的minQ和minH,如果可以,那么就修改
		minQ = current;
		minH = BestCushion;
	}
	return true;
}

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南叔先生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值