8.2 平衡线算法
每个程序员都会碰到顺序修改的问题,实际上,很多国外有关COBOL的图书已经讨论了这一主题。但是,很少的程序员或作者,如果有的话,编制了实际上通用的带有简短解释的完整程序。
平衡线算法至少需要3个文件:一个旧主文件、一个新主文件和一个或多个交易文件。假定交易文件和旧主文件是按相同的关键字顺序排列的。在旧主文件中,对于每个记录,关键字的值必须是唯一的,但对交易文件则可以是不唯一的;亦即,可以有几笔交易对应于同一主文件记录。
我们在本书中将平衡线算法使用到银行主文件的更新中,我们允许有5种类型的交易:即开户(增加)、销户(删除)、修改、存款和取款。一笔给定的交易只影响单个主文件记录,如前所述,对于相同的主文件记录可以有多笔交易,也可能有多个交易文件。交易文件和主文件都是以账号为关键字的,同一个账号在主文件中只有一条记录,但同一个账号在交易文件中可以出现多次,因为用户可能每天发生多笔存款或取款交易。
活动键的概念是这一算法的基础。活动键是旧主文件和当前正在处理的交易键的较小者。因此,如果交易键小于旧主文件链,活动键就等于交易键;如果交易链和旧主文件键相等,活动键就等于其中任意一个;最后,如果旧主文件键小于交易键,则活动键就设为旧主文件的。注意,这一技术很容易推广到多个交易文件的情形,活动键总是定义为当前处理的所有键的最小值。
下面程序包含整个主文件更新处理的伪代码,为简单起见,只有单个交易文件。开始时,从每个文件中读第1个记录,并决定第1个活动键。只有关键字等于活动键的记录才允许去参加主文件更新处理。最后,每个文件的关键字将等于HIGH-VALUES并且算法结束。
OPEN FILES READ TRANSACTION-FILE AT END MOVE HIGH-VALUES TO TRANSACTION-KEY READ OLD-MASTER-FILE AT END MOVE HIGH-VALUES TO OLD-MASTER-KEY CHOOSE FIRST ACTIVE-KEY DO WHILE ACTIVE-KEY NOT= HIGH-VALUES IF OLD-MASTER-KEY=ACTIVE-KEY MOVE OLD-MASTER-RECORD TO NEW-MASTER-RECORD READ OLD-MASTER-FILE AT END MOVE HIGH-VALUES TO OLD-MASTER-KEY ENDIF DO WHILE TRANSACTION-KEY=ACTIVE-KEY APPLY TRANSACTION TO NEW-MASTER-RECORD READ TRANSACTION-FILE AT END MOVE HIGH-VALUES TO TRANSACTION-KEY ENDDO IF NO DELETION WAS PROCESSED WRITE NEW-MASTER-RECORD ENDIF CHOOSE NEXT ACTIVE-KEY ENDDO CLOSE FILES STOP RUN
上面的主循环重复执行,直到活动键等于HIGH-VALUES;亦即,直到旧主文件和交易文件没有数据为止。如果当前旧主文件记录的关键字等于活动键,则旧主文件记录被传送到新主文件中,并从旧主文件中读出另一记录。第2个循环将所有等于活动键的交易应用到当前主文件记录中。每个交易处理完后,在这一内部循环中,重复读交易文件记录。当交易关键字不再等于活动键时,就检查是否要处理删除,如果没有,就写新主文件记录。选择下一个活动键,继续外面的循环。
下面的程序扩充了上面的逻辑以包括错误处理。尽管你可以假定交易文件本身是合法的,但在实际处理中仍会有别的错误情形出现,特别地,修改程序必须拒绝企图增加旧主文件已经存在的记录的交易(即重复的增加),也应当拒绝企图修改或删除不存在记录的交易(即错误地复制的交易键)。
完成这一错误处理的最容易的方法是通过给活动键的每一个值指定一分配状态,亦即,关键字的值要么已分配,要么没有分配。删除现存记录,将使状态从ON变成OFF;增加新记录将状态从OFF变成ON。企图增加一个状态已经为ON的键,表示是重复增加。按类似的方法,企图修改或删除分配状态为OFF的记录也隐含一种错误,因为交易键在旧主文件中不存在。
只有当KEY-ALLOCATED-SWITCH设置成YES时,记录才写到新主文件中。换句话说,删除只是将开关设置为NO,而不写记录。下面的伪代码除包含有KEY-ALLOCATED-SWITCH外,其他的与前面的讨论一样。
OPEN FILES READ TRANSACTION-FILE AT END MOVE HIGH-VALUES TO TRANSACTION-KEY READ OLD-MASTER-FILE AT END MOVE HIGH-VALUES TO OLD-MASTER-KEY CHOOSE FIRST ACTIVE-KEY DO WHILE ACTIVE-KEY NOT = HIGH-VALUES IF OLD-MASTER-KEY= ACTIVE-KEY MOVE ‘YES’TO KEY-ALLOCATED-SWITCH MOVE OLD-MASTER-RECORD TO NEW-MASTER-RECORD READ OLD-MASTER-FILE AT END MOVE HIGH-VALUES TO OLD-MASTER-KEY ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) MOVE ‘NO’TO KEY-ALLOCATED-SWITCH ENDIF DO WHILE TRANSACTION-KEY= ACTIVE-KEY EVALUATE TRANSACTION-CODE WHEN OPEN(开户) IF KEY-ALLOCATED-SWITCH= ‘YES’ WRITE ‘ERROR-Duplicate record’ ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) MOVE TRANSACTION-RECORD TO NEW-MASTER-RECORD MOVE ‘YES’TO KEY-ALLOCATED-SWITCH ENDIF WHEN UPDATE(修改客户资料) IF KEY-ALLOCATED-SWITCH= ‘YES’ PROCESS UPDATE ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) WRITE ‘ERROR-Record not Found’ ENDIF WHEN CLOSE(销户) IF KEY-ALLOCATED-SWITCH= ‘YES’ MOVE ‘NO’TO KEY-ALLOCATED-SWITCH PROCESS DELETION ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) WRITE ‘ERROR-Record not MATCH’ ENDIF WHEN DEPOSIT(存款) IF KEY-ALLOCATED-SWITCH= ‘YES’ MOVE ‘NO’TO KEY-ALLOCATED-SWITCH PROCESS DEPOSIT ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) WRITE ‘ERROR-Not Exist’ ENDIF WHEN WITHDRAW(取款) IF KEY-ALLOCATED-SWITCH= ‘YES’ MOVE ‘NO’TO KEY-ALLOCATED-SWITCH PROCESS WITHDRAW ELSE(ACTIVE-KEY IS NOT IN OLD-MASTER-FILE) WRITE ‘ERROR-Not Exist’ ENDIF WHEN OTHER WRITE ‘ERROR-INVALID TRANSACTION CODE’ END-EVALUATE READ TRANSACTION-FILE AT END MOVE HIGH-VALUES TO TRANSACTION-KEY ENDDO IF KEY-ALLOCATED-SWITCH= ‘YES’ WRITE NEW-MASTER-RECORD ENDIF CHOOSE NEXT ACTIVE-KEY ENDDO CLOSE FILES STOP RUN
读者应当相信上面代码的通用性,进一步说,对应于同一关键字的多个交易,可以按任意顺序出现。例如,如果交易是以增加和更正的顺序输入,记录将按相同的顺序增加和更正。但是,如果在增加的前面更正,则更正会标志为不匹配,而且只有增加发生作用。对于同一键的二次增加将导致第1次增加成功,第2次则标记为出错——重复增加。对于同一账户,交易可以按开户、修改、存款、取款和销户的顺序处理,但是,其他的组合顺序将产生错误信息,说明企图修改或删除旧主文件中不存在的记录。换句话说,对应于同一关键字的多笔交易可以按任意顺序出现,不要求对交易代码做第2次分类。