用JAVA实现插值查询的方法(算近似值,区间求法)
插值查询:如果有这样一张表,有一列叫水位,有一列叫库容,比如下面的图。
我现在想做这么一件事情:对于这个测站而言,当我输入某一个水位或者库容的时候,想要查询到对应的水位或者库容呢?
而这个值不一定是存在数据库中的,也许这只是一个推导出来的近似值呢?
算法要点:如果这个输入的值是位于数据库值的某一个区间内的话,那么取最小的区间,然后求这个区间内单位数量的值。
大家听得可能有点不太明白,我画张图。
呵呵,应该有点眉目了吧?这个第一步也是最重要的一步就是确定区间哦
算法的话很简单,用一句公式来概括就是
1.通过水位求库容:(单位水位所包含的库容)*(输入水位-这个水位左边区间的水位值)+这个水位左边区间的水位值
2.通过库容求水位:(单位库容所包含的库容)*(输入库容-这个库容左边区间的库容值)+这个库容左边区间的库容值
不废话,贴代码,用的是JAVA实现的
//插值查询法 @Override public String InterpolantQuery(ReservoirCapacityConditionParam param) { String finalVal=""; float finalVolumn=0; StringBuffer sb=new StringBuffer(); StringBuffer sd=new StringBuffer(); sb.append("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' "); if(param.getV()==""&¶m.getZ()!="") { sb.append(" and z='"+param.getZ()+"'"); } else if(param.getV()!=""&¶m.getZ()=="") { sb.append(" and v='"+param.getV()+"'"); } List<Object []> fromSTCD=this.daoHelper.findBySql(sb.toString()); //如果是已有数据,直接显示,否则算法查找 /*算法:通过库容查水位或通过水位查库容,如果输入的值在已有数据的某个范围内,则定位此数据的最小范围 * 1.比如输入120,有119~121,118~122这2个范围,则取119~121这个近似范围 * 2.假设输入的是水位,要查询库容,那么首先算出每一米水位在(1)范围内的库容,然后算出库容的增量,用这个增量加上这个区间内较低的库容 * 3.由于框架不能使用TOP关键字,所以(1)的范围的的取法:左边:查出比输入值小的所有数据,按大小的降序拍了,取最后一条,右边:查出比输入值大的所有数据,按升序排列,取最后一条*/ if(fromSTCD.size()==0) { //如果水位为空,则按照库容查询水位 if(param.getZ()=="") { if(param.getV().equals("0")) { //如果输入0,则不查询 } else { //查出左边区间的 List<Object []> left_fromSTCD=this.daoHelper.findBySql("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and v<'"+param.getV()+"' order by z asc"); //查出右边区间的 List<Object []> right_fromSTCD=this.daoHelper.findBySql("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and v>'"+param.getV()+"' order by z desc"); float beginZ=0,beginV=0; //水位 float endZ=0,endV=0; //库容 //如果左边区间为空 if(left_fromSTCD.size()==0) { //重置左边的区间 left_fromSTCD=this.daoHelper.findBySql(" select z,min(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' group by z order by z desc"); for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } //重置右边的区间 right_fromSTCD=this.daoHelper.findBySql("select z.* from (select top 2 z,min(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' and v>"+param.getV()+" group by z) z order by z.z asc"); for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } else { for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } } //如果右边区间为空 if(right_fromSTCD.size()==0) { //重置左边的区间 left_fromSTCD=this.daoHelper.findBySql("select z.* from (select top 2 z,max(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' and v<"+param.getV()+" group by z) z order by z.z desc"); for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } //重置右边的区间 right_fromSTCD=this.daoHelper.findBySql("select z,max(v) from hydro_curve_b where stcd='"+param.getStcd()+"' group by z order by z asc"); for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } else { for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } //计算每一格库容所包含的水位 float eachVolumn=1/((endV-beginV)/(endZ-beginZ)); float z=Float.parseFloat(param.getV()); //得到最终的水位 finalVolumn=(z-beginV)*eachVolumn+beginZ; } } //如果库容为空,则按照水位查询库容 else if(param.getV()=="") { if(param.getZ().equals("0")) { //如果输入0,则不做任何操作 } else { //查出左边区间的 List<Object []> left_fromSTCD=this.daoHelper.findBySql("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z<'"+param.getZ()+"' order by v asc"); //查出右边区间的 List<Object []> right_fromSTCD=this.daoHelper.findBySql("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z>'"+param.getZ()+"' order by v desc"); float beginZ=0,beginV=0; //水位,库容(left) float endZ=0,endV=0; //水位,库容(right) //如果输入的最小值比最数据库里的最小值小,那么取数据库里的最小值 //重置区间的原因是因为最小值是一个区间,用TOP2确定范围 if(left_fromSTCD.size()==0) { //重置左边的区间 left_fromSTCD=this.daoHelper.findBySql(" select MIN(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' group by v order by v desc"); for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } //重置右边的区间 right_fromSTCD=this.daoHelper.findBySql("select z.* from (select top 2 min(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z>"+param.getZ()+" group by v) z order by z.v asc"); for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } else { for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } } //如果输入的最大值比数据库里的最大值大,那么取数据库的最大值。 if(right_fromSTCD.size()==0) { //重置左边的区间 left_fromSTCD=this.daoHelper.findBySql("select z.* from (select top 2 max(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z<"+param.getZ()+" group by v) z order by z.v desc"); for(Object []obj:left_fromSTCD) { beginZ=Float.parseFloat(String.valueOf(obj[0])); beginV=Float.parseFloat(String.valueOf(obj[1])); } //重置右边的区间 right_fromSTCD=this.daoHelper.findBySql("select max(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' group by v order by v asc"); for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } else { for(Object []obj:right_fromSTCD) { endZ=Float.parseFloat(String.valueOf(obj[0])); endV=Float.parseFloat(String.valueOf(obj[1])); } } //计算每一格库容所包含的水位 //float eachVolumn=(endV-beginV)/(endZ-beginZ); float eachVolumn=1/((endZ-beginZ)/(endV-beginV)); float z=Float.parseFloat(param.getZ()); //得到最终的库容 //finalVolumn=(endZ-z)*eachVolumn+endZ; finalVolumn=beginV+eachVolumn*(z-beginZ); } } return String.valueOf(finalVolumn); } else { for(Object obj[]:fromSTCD) { if(param.getV()=="") { finalVal=String.valueOf(obj[1]); } else if(param.getZ()=="") { finalVal=String.valueOf(obj[0]); } } return finalVal; } }
其中也没什么难点,就是要注意一下左右区间重置的计算方法。
因为每次FOR遍历出里面的变量以后,前面的变量都会被后面的变量所覆盖,所以这里大家需要注意一下,合理使用top关键字和order by 是做出这个的关键,
好了,最后截图2张给大家看看效果,最后啰嗦一句,插值查询法虽然是算出来的,但是和数据库里的数据时息息相关的,是根据数据库里的数据算出的近似值。
比如下面的图,都是输入200的水位,但是结果不同,因为他们对应的区间不同。
__EOF__
作 者:ღKawaii
出 处:https://www.cnblogs.com/kmsfan/p/3946100.html
关于博主:一个普通的小码农,为了梦想奋斗
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!

出处:http://www.cnblogs.com/kmsfan
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
欢迎大家加入KMSFan之家,以及访问我的优酷空间!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?