火车车厢重排(栈式实现与队列实现)

问题描述:一列货运列车共有n节车厢,每节车厢将停放在不同的车站。假定n个车站的编号分别为1~n,货运列车按照第n站至第1站的顺序经过这些车站。车厢编号与他们的目的地一样。为了便于从列车上卸掉相应的车厢,必须重排车厢顺序,使得各车厢从前往后按编号1到n的次序排列。当所有车厢按照这种次序排列时,在每个车站只需卸掉最后一个车厢即可。我们在一个转轨站里完成重拍的工作,在转轨站有一个入轨,一个出轨和k个缓冲轨(位于入轨和出轨之间)。下面的图示就是一个转轨站,其中有3个缓冲轨,H1,H2,H3。

 

开始的时候,n节车厢从入轨处进入转轨站,转轨结束时各车厢从右往左按编号1到n的次序离开转轨站。如上图所示。

算法描述:为了重排车厢,需从前往后依次检查入轨上的所有车厢。如果正在检查的车厢就是下一个满足要求的车厢,可以直接把它放到出轨上。否则,则把它移动到缓冲轨上,直到按输出顺序要求轮到它的时候才可以将他放到出轨上。缓冲轨是按照FILO的方式使用的,因为车厢的进出都是在缓冲轨的顶端进行的。

在重排车厢过程中,仅允许以下活动:

1、车厢可以从入轨的前部移动到一个缓冲轨的顶部或者是出轨的左端

2、车厢可以从一个缓冲轨的顶部移动到出轨的左端

在将车厢放入缓冲轨的过程中,应该注意:有空的可以优先放,没空的缓冲轨时,要将新的车厢放在满足以下条件的缓冲轨中:在缓冲轨的顶部车厢编号比新车厢的编号大的所有缓冲轨中选择顶部车厢编号最小的那个,至于为什么,大家可以自己思考一下。

下面是代码:

文件"mystack.h"

#include <iostream>
using namespace std;

template<class T>
class My_stack;

template<class T>
class Node		//结点类
{
private:
	T data;
	Node<T> *next;
public:
	Node()
	{
		next=NULL;
	}
	Node(T d)
	{
		data=d;
		next=NULL;
	}
	friend My_stack<T>;
};

template<class T>
class My_stack
{
private:
	Node<T> *head;
public:
	My_stack()
	{
		head=new Node<T>();
	}
	
	bool empty() const
	{
		return (head->next==0);
	}
	
	void push(T d)	//入栈
	{
		Node<T> *p=new Node<T>(d);
		p->next=head->next;
		head->next=p;
	}
	
	T top()	//返回栈顶元素
	{
		if(empty())
		{
			cout<<"stack is empty."<<endl;
			exit(1);
		}
		Node<T> *p=head->next;
		T temp=p->data;
		return temp;
	}
	
	void pop()	//弹出栈顶元素
	{
		Node<T> *p=head->next;
		head->next=p->next;
		delete p;
	}
	
};

void OutPut(int& minH,int& minS,My_stack<int> H[],int k,int n);
bool Hold(int c,int& minH,int& minS,My_stack<int> H[],int k,int n);

bool Rail_Road(int p[],int n,int k)
{
	//k个缓冲轨,车厢初始排序为p[1...n]
	
	//创建与缓冲轨对应的链栈
	My_stack<int> *H;
	H=new My_stack<int>[k];
	
	int NowOut=1; //下一次要出轨的车厢
	int minH=n+1; //缓冲轨中编号最小的车厢
	int minS=k; //编号最小的车厢所在缓冲轨的编号

	//车厢重排序
	for(int i=0;i<n;i++)
	{
		if(p[i]==NowOut)
		{
			cout<<"Move car "<<p[i]<<" from input to output"<<endl;
			NowOut++;
			
			//从缓冲轨中输出
			while(minH==NowOut)
			{
				OutPut(minH,minS,H,k,n);
				NowOut++;
				if(NowOut==n+1) //输出全部车厢后返回,不然会造成内存非法访问
					return true;
			}
		}
		else
		{
			//将p[i]放入某个缓冲轨
			if(!Hold(p[i],minH,minS,H,k,n))
				return false;
		}
	}
	return true;
}

void OutPut(int& minH,int& minS,My_stack<int> H[],int k,int n)
{
	//该函数实现把一节车厢从缓冲轨送至出轨处
	//同时修改minH minS的值

	int c;

	//从栈中pop掉编号最小的车厢minH
	c=H[minS].top();
	H[minS].pop();

	cout<<"Move car "<<c<<" from holding track "<<minS+1<<" to output "<<endl;

	//检查所有链栈,搜索新的minH minS
	minH=n+1;
	
	for(int i=0;i<k;i++)
		if( (!H[i].empty()) && (H[i].top()<minH) )
		{
			minH=H[i].top();
			minS=i;
		}
}

bool Hold(int c,int& minH,int& minS,My_stack<int> H[],int k,int n)
{
	//该函数是将车厢c放入缓冲轨中

	//为车厢c寻找最优缓冲轨
	int BestTrack=k;//初始化
	int BestTop=n+1; //最优缓冲轨的栈顶车厢编号

	int x;

	//扫描缓冲轨
	for(int i=0;i<k;i++)
	{
		if(!H[i].empty())
		{
			x=H[i].top();
			if(c<x && x<BestTop)
			{
				BestTop=x;
				BestTrack=i;
			}
		}
		else
		{
			//H[i]为空时
			if(BestTrack==k)
				BestTrack=i;
		}
	}

	if(BestTrack==k) //没有可用的缓冲轨
		return false;

	H[BestTrack].push(c);
	cout<<"Move car "<<c<<" from input to holding track "<<BestTrack+1<<endl;

	//必要时修改minH和minS
	if(c<minH)
	{
		minH=c;
		minS=BestTrack;
	}

	return true;
}

主函数

#include "mystack.h"

int main()
{
	int p[9]={3,6,9,2,4,7,1,8,5};
	if(Rail_Road(p,9,3))
		cout<<"车厢重排序成功"<<endl;
	else
		cout<<"车厢重排序失败"<<endl;
	return 0;
}

输出结果:

Move car 3 from input to holding track 1
Move car 6 from input to holding track 2
Move car 9 from input to holding track 3
Move car 2 from input to holding track 1
Move car 4 from input to holding track 2
Move car 7 from input to holding track 3
Move car 1 from input to output
Move car 2 from holding track 1 to output
Move car 3 from holding track 1 to output
Move car 4 from holding track 2 to output
Move car 8 from input to holding track 1
Move car 5 from input to output
Move car 6 from holding track 2 to output
Move car 7 from holding track 3 to output
Move car 8 from holding track 1 to output
Move car 9 from holding track 3 to output
车厢重排序成功
Press any key to continue

 

如果缓冲站的结构如下所示:

那么缓冲轨就不是FILO 而是FIFO了 那么就要用队列来实现车厢重排了,算法的描述和栈实现的基本一样的,只是OutPut 和 Hold 函数改了一下,将一截车厢移动到缓冲轨时,车厢c应该移动到这样的缓冲轨中:该缓冲轨中现有各车厢的编号均小于c,如果有多个缓冲轨都满足这一条件,那么选择其中左端车厢编号最大的那个缓冲轨,否则选择一个空的缓冲轨(如果存在的话)

下面是代码:

文件"myqueue.h"

#include <iostream>
using namespace std;

template<class T>
class My_queue;

template<class T>
class Node
{
private:
	T data;
	Node<T> *next;
public:
	Node()
	{
		next=0;
	}
	Node(T d)
	{
		data=d;
		next=0;
	}
	friend My_queue<T>;
};

template<class T>
class My_queue
{
private:
	Node<T> *tail;
public:
	My_queue()
	{
		tail=new Node<T>();
		tail->next=tail;
	}

	bool empty()
	{
		return (tail->next==tail);
	}

	void push(T d)
	{
		Node<T> *p=new Node<T>(d);
		p->next=tail->next;
		tail->next=p;
		tail=p;
	}
	
	T front()
	{
		if(empty())
		{
			cout<<"queue is empty!"<<endl;
			exit(0);
		}
		Node<T> *p=tail->next;
		T data=p->next->data;
		return data;
	}
	
	T back()
	{
		if(empty())
		{
			cout<<"queue is empty!"<<endl;
			exit(0);
		}
		T data=tail->data;
		return data;
	}
	
	void pop()
	{
		Node<T> *p=tail->next;
		Node<T> *q=p->next;
		p->next=q->next;
		if(q==tail)
			tail=p;
		delete q;
	}
	
};

void OutPut(int& minH,int& minQ,My_queue<int> H[],int k,int n);
bool Hold(int c,int& minH,int& minQ,My_queue<int> H[],int k);

bool Rail_Road(int p[],int n,int k)
{
	//k个缓冲轨,车厢初始排序为p[1...n]
	
	//创建与缓冲轨对应的队列
	My_queue<int> *H;
	H=new My_queue<int>[k];
	
	int NowOut=1; //下一次要出轨的车厢
	int minH=n+1; //缓冲轨中编号最小的车厢
	int minQ=k; //编号最小的车厢所在缓冲轨的编号

	//车厢重排序
	for(int i=0;i<n;i++)
	{
		if(p[i]==NowOut)
		{
			cout<<"Move car "<<p[i]<<" from input to output"<<endl;
			NowOut++;
			
			//从缓冲轨中输出
			while(minH==NowOut)
			{
				OutPut(minH,minQ,H,k,n);
				NowOut++;
				if(NowOut==n+1) //输出全部车厢后返回
					return true;
			}
		}
		else
		{
			//将p[i]放入某个缓冲轨
			if(!Hold(p[i],minH,minQ,H,k))
				return false;
		}
	}
	return true;
}

void OutPut(int& minH,int& minQ,My_queue<int> H[],int k,int n)
{
	//该函数实现把一节车厢从缓冲轨送至出轨处
	//同时修改minH minQ的值

	int c;

	//从队列中pop掉编号最小的车厢minH
	c=H[minQ].front();
	H[minQ].pop();

	cout<<"Move car "<<c<<" from holding queue "<<minQ+1<<" to output "<<endl;

	//检查所有队列,搜索新的minH minQ
	minH=n+1;
	
	for(int i=0;i<k;i++)
		if( (!H[i].empty()) && (H[i].front()<minH) )
		{
			minH=H[i].front();
			minQ=i;
		}

}

bool Hold(int c,int& minH,int& minQ,My_queue<int> H[],int k)
{
	//该函数是将车厢c放入缓冲轨中

	//为车厢c寻找最优缓冲轨
	int BestQueue=k;//初始化缓冲轨的编号
	int BestLast=0; //最优缓冲轨的队尾车厢编号

	int x;

	//扫描缓冲轨
	for(int i=0;i<k;i++)
	{
		if(!H[i].empty())
		{
			x=H[i].back();
			if(c>x && x>BestLast)
			{
				BestLast=x;
				BestQueue=i;
			}
		}
		else
		{
			//H[i]为空时
			if(BestQueue==k)
				BestQueue=i;
		}
	}

	if(BestQueue==k) //没有可用的缓冲轨
		return false;

	H[BestQueue].push(c);
	cout<<"Move car "<<c<<" from input to holding queue "<<BestQueue+1<<endl;

	//必要时修改minH和minS
	if(c<minH)
	{
		minH=c;
		minQ=BestQueue;
	}

	return true;
}

主函数:

#include "myqueue.h"

int main()
{
	int p[9]={3,6,9,2,4,7,1,8,5};
	if(Rail_Road(p,9,3))
		cout<<"车厢重排序成功"<<endl;
	else
		cout<<"车厢重排序失败"<<endl;
	return 0;
}

测试结果:

Move car 3 from input to holding queue 1
Move car 6 from input to holding queue 1
Move car 9 from input to holding queue 1
Move car 2 from input to holding queue 2
Move car 4 from input to holding queue 2
Move car 7 from input to holding queue 2
Move car 1 from input to output
Move car 2 from holding queue 2 to output
Move car 3 from holding queue 1 to output
Move car 4 from holding queue 2 to output
Move car 8 from input to holding queue 2
Move car 5 from input to output
Move car 6 from holding queue 1 to output
Move car 7 from holding queue 2 to output
Move car 8 from holding queue 2 to output
Move car 9 from holding queue 1 to output
车厢重排序成功
Press any key to continue

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值