软件构造——关于等价性

关于等价性

在学到ADT的等价性的时候,有三条基本原则,即:自反、传递、对称。
其中,自反和对称往往是满足的,但传递常常出现一些问题。比如,在课堂上就出现了这样一个例子:
在这里插入图片描述

显然,这个equals()不满足于传递性,问题就出现所谓的误差值CLOCK_SKEW上。由于误差值在传递的过程中会不断累加,从而导致了最终超过可容忍的误差值的情况。

但这种设置误差值的方法是经常使用的,比如在ACM的很多计算几何题目中,就大量采用了误差值的方法。以二维为例:设一个误差值eps(通常很小),对两点A(x1,y1)和B(x2,y2),当这两点间距离 d i s ( A , B ) = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 ≤ e p s dis(A,B)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2} \leq eps dis(A,B)=(x1x2)2+(y1y2)2 eps 时,将A与B视为同一点。

这个方法是非常实用的,因为它很好地解决了计算机浮点运算中精度误差的问题。但这样的代价就是破坏了等价关系的传递性。

从某种意义上来说,我们经常不得不对程序的实用性与准确性进行取舍,这一点在等价性关系上展现得很好。

解决方案

那么,有没有既满足实用性,又满足等价性的解决方案呢?我有一个初步的想法。
以一维线段为例:设左端点为0,右端点为10。将其等距地划分为n段,则每个区间形成了一个等价类。

  • equals(A,B):当A和B在同一个区间内时,认为A和B是等价的。否则A和B不等价。

显然,这个equals()是满足等价性的三个原则的:A与B等价,B与C等价,则说明ABC在同一组内,那么A与C等价。
这个equals()是运用了分块算法的想法:块内统一管理。但面对块间的情况时,equals()就不能发挥作用了:只要A与B在不同的块内,哪怕 d i s ( A , B ) ≤ e s p dis(A,B) \leq esp dis(A,B)esp,A与B也不等价。这就是对实用性的牺牲。
同时,我们发现n要尽量的大。
在这里插入图片描述
上图中分别为n=2和n=5的情况,显然n=5的情况中equals()更为精准,不容易出现跨块的情况。

改进方案

正如数学上的插值法所说明的:当等距的方法到达瓶颈后,不妨试一下不等距的情况。
由于我们开发的是软件,面对的是实际情况的数据,而实际情况的数据又一般具有一些规律,如:符合正态分布。因此我们可以根据数据的分布情况来改变分块的策略。
不妨假设输入数据满足正态分布:
在这里插入图片描述
对上图进行改造:
在这里插入图片描述
可以看到2、3两条线段中都是n=5,但是由于数据常常出现在中间部分,两头的数据会较少,因此线段3改变了策略,将端点设置在了{1,2,8,9}。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值