本文中的两道题目都是鄙人数据结构课程里的作业,仅以此博客记录个人的解题过程。
问题一:利用栈来改变火车的行驶顺序。
分析这个问题,N列给定顺序的火车在经过火车站后行驶顺序发生了变化,那么可以想到,这些火车在进入火车站后,如果其出站的顺序较后,则可以在火车站中停靠,让行驶顺序较前的火车先出站,来达到更换火车行驶顺序的目的。这就可以联想到一个很重要的存储结构——栈。栈的特点是“后进先出”,把暂时不需要出站的火车压入栈中保存,把需要出站的火车从栈中弹出。
首先,定义两种数据类型:节点和链栈,分别来表示火车和火车站。
问题的核心在于:何时将火车停靠在火车站中,何时停靠在火车站中的火车出站。
如果,当前将要进站的火车刚好是当前需要出站的火车,该火车可以直接出站,不需要进栈保存,可以理解为进站后马上出站;
如果当前将要进站的火车不是当前需要出站的火车,那么火车将进站停靠;
另外要注意的是,在当前进站的火车匹配到当前需要出站的火车时,当前需要出站的火车将发生变更,此时火车站中停靠最前火车可能是当前将要出站的火车,所以要不断将火车站中停靠最前的火车与当前需要出站的火车进行匹配。
当所有匹配结束,即不再有火车满足出站条件时,如果火车站中没有停靠的火车,则火车的出站顺序成立;
如果火车站中仍然有停靠的火车,则火车的出站顺序不成立。以下为该算法的代码:
int SeqLegal(int in[], int out[], int num, Stack* S){
int *Out_id = out; //当前将要出站的列车序号
StackNode* Node;
Node = S->top->next;
for(int i = 0; i < num; i++){ //当前将要进站的列车序号与当前将要出站的列车序号相同,可以直接忽略,当前将要出站列车变更
if(in[i] == *Out_id){
Out_id++;
while(!StackEmpty(S) && GetTop(S) == *Out_id){ //如果栈不为空而且栈顶元素序号与当前将要出站列车序号相同,则弹出栈顶元素
Pop(S);
Node = S->top->Next;
Out_id++;
}
}
else{
Push(S, in[i]); //当前将要进站的列车序号与当前将要出站的列车序号不相同,列车进栈保存,当前将要出站列车不变
}
}
while(Node && (Node->ID == *Out_id)){ //比较栈顶元素序号与当前将要出站列车序号是否相同,相同则弹出栈顶元素,继续比较下一对序号,直至栈空或者序号不同
Pop(S);
Node = S->top->Next;
Out_id++;
}
if(StackEmpty(S))
return 1; //栈为空,列车出站序列可以完全匹配
else
return 0; //栈非空,列车出站序列不能完全匹配
}
以示例的火车顺序为例:
火车1进站,其不为当前需要出站的火车,则将其停
靠在火车站中。
火车2进站,其刚好为当前需要出站的火车,则火车2出站。当前需要出站火车变更为火车4,与火车站中的火车1不匹配。
火车3进站,停靠在火车站中。
火车4进站,刚好为当前需要出站火车,则火车4出站,当前需要出站火车变更为3,与火车站中停靠最前的火车3匹配,则火车3出站,当前需要出站的火车变更为1,与火车站中停靠最前的火车1匹配,火车1出站。
此时,火车全部进站和出站,火车站中无停靠火车,那么该出站序列成立。
再来分析另外一个例子:
进站火车序列为1234,出站火车序列为4231。
火车1234依次进站后,当前需要出站火车与停靠最前的火车4匹配,火车4出站。
当前出站需要出站火车变更为火车2,而停靠最前火车为3,两者不能匹配,此时剩余的全部火车都不能出站,那么该出站序列不成立。
问题二:求解能够正确调整火车行驶顺序所需的最少轨道数量。
分析这个问题,N列给定顺序的火车在进入缓冲轨道后,其行驶顺序发生了变化。**可以知道,先进入某一条缓冲轨道的火车将优先从出口行驶出来,即对于各缓冲轨道的火车,都满足“先进先出”的规则,那么我们可以联想到队列这一数据结构。**将每一条缓冲轨道看成一个队列,轨道中的火车有序排队。
先定义两种数据类型,节点和链队列,分别表示火车和缓冲轨道。
问题的核心在于:
一、要使火车在经过缓冲轨道后按序号从小到大的顺序行驶,再结合队列“先进先出”的要求,就需要在每条缓冲轨道中队前火车的序号小于队后火车的序号,即每条缓冲轨道中的火车序号呈升序排列。
二、再考虑求解轨道的最小数量。要使缓冲轨道数量最少,需要将每条缓冲轨道中的火车数量最大化,那么在选择火车轨道时,就要将火车放入与其序号差值最小的轨道。举个例子:
如果已有两条轨道,分别有火车4和火车2,又有火车5和火车3先后从入口进入,此时如果将火车5放入火车2的轨道,那么火车3只能进入新的无车轨道,因为在已有的两条轨道中末端火车的序号(分别为火车4和火车5)均大于3,此时缓冲轨道数量为3;而如果将火车5放入火车4的轨道,那么就可以将火车3放入火车2的轨道,此时缓冲轨道数量为2。
寻找最适合轨道的代码如下:
int FindClosestQueue(Queue *RailQueue[],int UsedQueue,int CurTrain){
int closestIdx = -1; //最合适的轨道初始化为-1
int Rear_Id; //队尾元素
int D_value[UsedQueue]; //记录当前火车序号与每个轨道队尾火车序号的差值
for(int i = 0; i < UsedQueue; i++) //遍历每个使用过的轨道
{
if(CurTrain > GetRear(RailQueue[i])) //当前火车序号大于队尾火车序号
{
Rear_Id = GetRear(RailQueue[i]);
D_value[i] = CurTrain - Rear_Id; //记录两车的序号差值
}
else{
D_value[i] = 0; //将差值记录为0,便于求得最小差值
}
}
for(int i = 0; i < UsedQueue; i++) //遍历差值数组,除0外差值记录最小的轨道为最适合轨道
{
if(D_value[i] > 0) //如果差值记录大于0,该轨道为候选轨道
{
if(closestIdx < 0) //之前未找到最适合轨道
{
closestIdx = i; //最适合轨道赋值为当前候选轨道
}
else{ //之前已找到最适合轨道
if(D_value[i] < D_value[closestIdx]) //比较两个轨道的差值记录,如果当前候选轨道差值较小,将最适合轨道赋值为当前候选轨道
{
closestIdx = i;
}
}
}
}
return closestIdx; //返回最适合轨道序号,不存在最适合轨道时返回-1
}
然后将火车插入相应轨道,最终使用的轨道数量即为最小缓冲轨道数量:
int MinBufferQueue(int out[], int num){
Queue *RailQueue[num]; //指针数组,记录各缓存轨道的火车,有与火车数相等的轨道数时一定可行
int closestIdx;
int UsedQueue = 0; //已使用的队列数
int ArrangedTrain = 0; //已安排的火车数
for(int i = 0; i < num; i++){
RailQueue[i] = InitQueue(); //初始化火车队列
}
for(int i = 0; i < num; i++)
{
closestIdx = FindClosestQueue(RailQueue,UsedQueue,out[i]); //寻找当前火车的最适合轨道
if(closestIdx == -1) //不存在最适合轨道
{
EnQueue(RailQueue[UsedQueue], out[i]); //当前火车入队新火车轨道
UsedQueue++; //已使用的队列数增加
ArrangedTrain++; //已安排的火车数增加
}
else //存在最适合轨道
{
EnQueue(RailQueue[closestIdx], out[i]); //当前火车入队最适合轨道
ArrangedTrain++; //已安排的火车数增加,已使用的队列数不变
}
}
return UsedQueue; //返回已使用的队列数
}
敲黑板!!!萌新首次尝试撰写博客,文章内容涉及到的编程知识也非常基础,个人的代码能力也是比较有限,在此欢迎各位大佬交流指正。