1. 程式人生 > >火車車廂重排(棧式實現與佇列實現)

火車車廂重排(棧式實現與佇列實現)

問題描述:一列貨運列車共有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