一列货运列车共有n节车厢,每节车厢将停放在不同的车站。假定n个车站的编号(由远到近)依次为1-n,即货运列车按照第n站至第1站的次序经过这些车站。为了便于从列车上卸掉相应的车厢,车厢的编号应与车站的编号相同,使各车厢从前至后按编号1-n的次序排序,这样,在每个车站只需卸掉最后一节车厢即可。因此,需要对给定任意次序的车厢进行重新排列。
实现车厢重新排列的目的,可以通过转轨站来完成,在转轨站中有一个入轨、一个出轨和k个缓冲轨,缓冲轨位于入轨和出轨之间。开始时,任意的n节车厢入轨进入转轨站,转轨结束时各车厢按照编号1至n的次序离开转轨站进入出轨。假定缓冲轨按先进先出的方式运作,可将它们视为k个队列,并且禁止将车厢从缓冲轨移至入轨,也禁止从出轨移至缓冲轨。
基于队列及转轨站两种抽象数据类型,在分别对k个队列初始化、且设当前输出车厢号nowout=1、入轨车厢序号i=0,n节车厢重排的算法大致描述如下:
While(nowout<=n)
{
如果各缓冲轨队列中有队头元素等于nowout
则输出该车厢;
nowout++;
否则,求小于car[i]的最大队尾元素所在队列的编号j;
如果j存在
则把car[i]移至缓冲轨j;
否则
如果至少有一个空缓冲轨
则把car[i]移至一 个空缓冲轨;
否则,车厢无法重排,算法结束。
i++;
}
车厢已重排,算法结束。
为由于车厢的数量并不确定,为避免溢出,本例采用带头结点的单链表实现队列的抽象数据类型。
单链表实现的抽象数据LinkQueue.h文档如下:
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
//链队列结点结构
struct LinkNode {
QElemType data;
LinkNode *next;
};
//带头结点的链队列结构
struct LinkQueue {
LinkNode *front; //队头指针
LinkNode *rear; //队尾指针
};
//构造一个空的链队列。
void InitQueue( LinkQueue &Q )
{
Q.front = Q.rear = new LinkNode ;
Q.front->next = NULL;
}//LinkQueue
//将链队列清空。
void ClearQueue( LinkQueue &Q )
{
LinkNode *p;
while ( Q.front->next != NULL )
{
p = Q.front->next;
Q.front->next = p->next;
delete p;
}
Q.rear = Q.front;
}
//链队列结构销毁。
void DestroyQueue( LinkQueue &Q )
{
ClearQueue( Q ); //成员函数Clear()的功能是释放链表中的所有元素结点
delete Q.front;
Q.front = Q.rear = NULL;
}
//判链队列是否为空,若为空,则返回true,否则返回false。
bool QueueEmpty( LinkQueue Q )
{
return Q.front == Q.rear;
}
//返回链队列中元素个数。
int QueueLength( LinkQueue Q )
{
int i = 0;
LinkNode *p = Q.front->next;
while ( p != NULL )
{
i++;
p = p->next;
}
return i;
}
//取链队列队头元素的值。先决条件是队列不空。
QElemType GetHead( LinkQueue &Q )
{
return Q.front->next->data;
}
//取链队列队尾元素的值。先决条件是队列不空。
QElemType GetLast( LinkQueue &Q )
{
return Q.rear->data;
}
//链队列入队,插入e到队尾。
void EnQueue( LinkQueue &Q, QElemType e )
{
LinkNode *p;
p = new LinkNode ;
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
}
//链队列出队。先决条件是队列不空。
bool DeQueue( LinkQueue &Q,QElemType &e )
{
if ( QueueEmpty( Q ) )
return false;
LinkNode *p = Q.front->next;
Q.front->next = p->next;
e = p->data;
if ( p == Q.rear )
Q.rear = Q.front; //若出队后队列为空,需修改Q.rear。
delete p;
return true;
}
#endif
转轨站抽象数据类型的实现,数据结构设计为队列的指针向量,其Realign.h文件如下:
#ifndef _Realign_H_
#define _Realign_H_
#include "LinkQueue.h"
struct CTrackStation {
LinkQueue *pTracks; //各缓冲轨(队列)
int trackCount; //缓冲轨数量
};
//初始化k个轨道
void InitCTrackStation(CTrackStation &TS,int &k) {
TS.trackCount = k;
TS.pTracks = new LinkQueue[ k ];
for ( int i = 0; i < k; i++ )
InitQueue( TS.pTracks[ i ] );
}
//销毁k个轨道
void DestroyCTrackStation( CTrackStation &TS )
{
for ( int i = 0; i < TS.trackCount; i++ )
DestroyQueue(TS.pTracks[i]);
delete[] TS.pTracks;
TS.trackCount = 0;
}
//将车厢car移到其中一个可用缓冲轨,成功返回true。
bool HoldIn( CTrackStation &TS, int &car, int &k )
{
int bestTrack = - 1; //目前最优的缓冲轨
int bestLast = - 1; //最优缓冲轨中的最后一节车厢
int i;
for ( i = 0; i < TS.trackCount; i++ )
{
//查找最优缓冲轨
if ( ! QueueEmpty( TS.pTracks[ i ] ) )
{
int last; //车厢编号
last = GetLast( TS.pTracks[ i ] );
if(car > last && last > bestLast)
{
//缓冲轨i尾部的车厢号较大
bestLast = last;
bestTrack = i;
}
}
}
if ( bestTrack == -1 )
{
//未找到合适缓冲轨,查找空闲缓冲轨
for ( i = 0; i < TS.trackCount; i++ )
if ( QueueEmpty( TS.pTracks[ i ] ) )
{
bestTrack = i;
break;
}
}
if ( bestTrack == -1 )
return false; //没有可用的缓冲轨
EnQueue( TS.pTracks[ bestTrack ], car );
k = bestTrack;//将车厢ca移入k号缓冲轨
return true;
}
//将缓冲轨中车厢car移出,成功返回true。
bool HoldOut( CTrackStation &TS, int &car, int &k )
{
int i;
for ( i = 0; i < TS.trackCount; i++ )
{
if ( ! QueueEmpty( TS.pTracks[ i ] ) )
{
int headCar; //车厢编号
headCar = GetHead( TS.pTracks[ i ] );
if ( headCar == car )
{
DeQueue( TS.pTracks[ i ], headCar );
k = i; //将缓冲轨中车厢car从k号轨移出
return true;
}
}
}
return false;
}
#endif
完整是程序包含对n节车厢进行重排的RealignCTrackStation函数及主函数等。
车厢重排.cpp文档如下:
#include
using namespace std;
typedef int QElemType;
#include "Realign.h"
//利用k个缓冲轨,对n节车厢重排
bool RealignCTrackStation( CTrackStation &TS, int *A, int &n )
{
int k, nowOut = 1, i = 0;
while ( nowOut <= n )
{
if ( HoldOut(TS, nowOut, k ) )
{
cout << nowOut << " 号车厢从 "<< k << "号缓冲轨出队" << endl;
nowOut++;
continue;
}
if ( i >= n || ! HoldIn( TS, A[i], k ) )
return false;
cout << A[ i ] << " 号车厢进入 " << k << " 号缓冲轨" << endl;
i++;
}
return true;
}
int main()
{
int i, m, k;
cout << "请输入需重排的车厢数:";
cin >> m;
int car, A[ m ];
cout << "请依次输入需重排的车厢序列编号:";
for ( i = 0; i < m; i++ )
cin >> A[i];
cout << "请输入缓冲轨(队列)的数目:";
cin >> k;
cout << endl;
CTrackStation trackStation; //构建缓冲轨站
bool ok = false;
do
{
InitCTrackStation( trackStation, k );
if ( RealignCTrackStation( trackStation, A, m ) )
{
//利用缓冲轨站重排车厢
ok = true;
cout << endl << "车厢已重排!" << endl;
}
else
{
DestroyCTrackStation( trackStation );
cout << "缓冲轨的数目为"<< k <<"时,因车厢无法重排,请重输缓冲轨的数目:";
cin >> k;
cout << endl;
}
}while ( ! ok );
DestroyCTrackStation( trackStation );
return 0;
}