(JAVA)仿拼多多砍价算法
前⾔
先上执⾏完毕后的控制台输出截图:
我的业务流程是,当⽤户发起⼀个砍价,先使⽤这个⽅法⽣成对应⼈数的砍价⾦额集合(我们的⾦额对应⼈数是⽀持配置的,例如900元-1000元需要70个⼈)放⼊redis(异步写⼊db),key为⽤户id,当有⼈进⼊砍价,从redis拿出集合随机取⼀个⾦额写⼊缓存(key为⽤户id,此缓存是砍价记录,同时异步写⼊db,⽤于记录;把此⾦额从原先的集合中抹除),砍价结束把集合从缓存中删除。
package com.dq.utils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 获取砍价的集合公共⽅法
* 2018年6⽉4⽇上午9:35:57
* version 1.0
*
* @author lwf
*/
public class BargainCommonUtils {
private static final Logger logger = Logger(BargainCommonUtils.class);
/**
* 砍价算法优化,避免死循环和空指针
* <br/>为避免价格⽣成出错,要求:count<=100;price/count>=0.08
* <br/>2018年8⽉14⽇上午9:54:39
* <br/>version 1.0
* <br/>@author lwf
bigdecimal转换为integer* <br/>@param count
* <br/>@param price
* <br/>@param finalPrice
* <br/>@return
*/
public static List<BigDecimal> getBargainList(Integer count, BigDecimal price, BigDecimal finalPrice) {
List<BigDecimal> list = new BargainCommonUtils().getTempBargainList(count, price, finalPrice);
int i = 0;
while (list == null || list.size() == 0 || list.size() != count) {
list = new BargainCommonUtils().getTempBargainList(count, price, finalPrice);
i++;
if (i > 50000) {
logger.info("砍价集合⽣成超时!请重试或重新设定价格/次数⽐例!");
logger.info("砍价集合⽣成超时!请重试或重新设定价格/次数⽐例!");
break;
}
}
return list;
}
/
*
* 获取砍价的价格集合
* <br/>2018年6⽉7⽇下午4:32:31
* <br/>version 1.0
*  <br/>@author lwf
*/
public static  List<BigDecimal> getTempBargainList(Integer count, BigDecimal price, BigDecimal finalPrice) {
BigDecimal sourcePrice = price;
sourcePrice = sourcePrice.subtract(finalPrice);    // 实际要折扣掉的⾦额
sourcePrice = sourcePrice.setScale(2, RoundingMode.HALF_DOWN);// 把多余的⼩数点去掉
ArrayList<BigDecimal> tempPrices = new ArrayList<>();//  实际被砍掉的价格集合
Map<String, BigDecimal> lastPrice = new HashMap<>();//  最后⼀次的砍价剩余的价格
int sum = 0;// 实际砍价次数
ArrayList<BigDecimal> finalPrices = new ArrayList<>();    // 最终所需要的砍价集合
finalPrice = new BigDecimal(0);
BigDecimal divisor = new BigDecimal(count);
//  获取砍价的平均值
int countTmep = 2;
getPirces(sourcePrice, countTmep, tempPrices, finalPrice, lastPrice);
tempPrices.("lastPrice"));
sum = tempPrices.size();
if (sum > count) {    // 如果实际砍价次数⼤于预期次数,则再进⾏处理
int temp = sum - count;// 相差次数
BigDecimal sumPrice = new BigDecimal(0.00);
for (int i = 0; i < tempPrices.size(); i++) {
if (i < tempPrices.size() - temp) {
finalPrices.(i));
} else {
sumPrice = sumPrice.(i));    // 多余的砍价
}
}
//  把多余的砍价平均分散到前count中的砍价
BigDecimal divide = null;
try {
divide = sumPrice.divide(new BigDecimal(count), 2, RoundingMode.HALF_DOWN);
} catch (Exception e) {
logger.Message());
e.printStackTrace();
}
divide = divide.setScale(2, RoundingMode.HALF_DOWN);
for (int i = 0; i < finalPrices.size(); i++) {
BigDecimal add = (i).add(divide);
finalPrices.set(i, add);
}
} else if (sum == count) {
finalPrices = tempPrices;
} else {
return null;
}
}
//  价格矫正补总差价,多减少增
BigDecimal totalPrice = new BigDecimal(0);
for (BigDecimal bd : finalPrices) {
totalPrice = bd.add(totalPrice);
}
logger.info("价格矫正前的totalPrice:" + totalPrice);
//  如果集合中的总价⼤于实际原价,则把集合中任意⼀个⼤于这个差价的价格减去差价(误差都不会超过0.1)
int inFlag = 0;
if (totalPricepareTo(sourcePrice) > 0) {
BigDecimal subtract = totalPrice.subtract(sourcePrice);
for (int i = 0; i < finalPrices.size(); i++) {
if ((i)pareTo(subtract) > 0) {    // 集合中的⼤于这个差价的价格
BigDecimal changedPrice = (i).subtract(subtract);
finalPrices.set(i, changedPrice);
inFlag = 1;
break;
}
}
}
if (totalPricepareTo(sourcePrice) < 0) {    // 如果集合中的总价⼩于等于实际原价,则把集合中最后⼀个价格加上差价(误差都不会超过0.1)
BigDecimal subtract = sourcePrice.subtract(totalPrice);
BigDecimal sourceLastPrice = (finalPrices.size() - 1);
BigDecimal changedPrice = sourceLastPrice.add(subtract);
finalPrices.set(finalPrices.size() - 1, changedPrice);
inFlag = 1;
}
if (totalPricepareTo(sourcePrice) == 0) {
inFlag = 1;
}
if (inFlag == 0) {    // 如果没有价格⼤于这个差价,则再完整的调⼀次本⽅法
return null;
} else {
logger.info("sourcePrice:" + sourcePrice);
logger.info("*********************************");
totalPrice = new BigDecimal(0);
for (BigDecimal bd : finalPrices) {
totalPrice = bd.add(totalPrice);
}
logger.info("预期砍价次数:" + count + " 实际砍价次数:" + finalPrices.size() + " 价格矫正后的totalPrice:" + totalPrice);
logger.Array()));
return finalPrices;
}
}
/**
* 获取被砍的价格集合
* <br/>2018年6⽉4⽇下午3:19:07
* <br/>version 1.0
* <br/>@author lwf
* <br/>@param sourcePrice 原价
* <br/>@param avgPrice 砍价平均值:原价/砍价次数=砍价平均值
* <br/>@param tempPrices 砍价价格集合
* <br/>@param finalPrice 最终价
*/
public static  void getPirces(BigDecimal sourcePrice, int countTemp, List<BigDecimal> tempPrices, BigDecimal finalPrice, Map<String, BigDecimal> lastPrice) {        Random r = new Random();
double d = sourcePrice.divide(new BigDecimal(++countTemp), 2, RoundingMode.HALF_DOWN).doubleValue();
if (tempPrices.size() > 0 && tempPrices.size() % 4 == 0) {
if (tempPrices.size() > 0 && tempPrices.size() % 4 == 0) {
countTemp = countTemp - 3;
}
Double randomPrice = r.nextDouble() * d + 0.01;    // 例如:⽣成0到9.99之间的随机数
BigDecimal bargainPrice = new BigDecimal(randomPrice); // 被砍掉的价格
bargainPrice = bargainPrice.setScale(2, RoundingMode.HALF_DOWN);
BigDecimal surplusPrice = sourcePrice.subtract(bargainPrice);    // 剩余价格
if (surplusPricepareTo(finalPrice) <= 0) {
return;
}
tempPrices.add(bargainPrice);
lastPrice.put("lastPrice", surplusPrice);
getPirces(surplusPrice, countTemp, tempPrices, finalPrice, lastPrice);
}
/
* @Test
public void testBargain() {
int count = 100;
BigDecimal price = new BigDecimal(7);
BigDecimal finalPrice = new BigDecimal(0);
List<BigDecimal> list = new BargainCommonServiceImpl().getTempBargainList(count, price, finalPrice);            int i = 0;
while(list==null || list.size()==0||list.size()!=count) {
list = new BargainCommonServiceImpl().getTempBargainList(count, price, finalPrice);
i ++;
if(i>50000) {
logger.info("砍价集合⽣成超时!请重试或重新设定价格/次数⽐例!");
System.out.println("砍价集合⽣成超时!请重试或重新设定价格/次数⽐例!");
break;
}
}
System.out.println(i);
}*/
public static void main(String[] args) {
int count = 10;
BigDecimal price = BigDecimal.valueOf(7L);
BigDecimal finalPrice =BigDecimal.ZERO;
List<BigDecimal> list = TempBargainList(count, price, finalPrice);
list.forEach(bigDecimal -> {
System.out.String());
});
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。