初探12306售票算法(一)- 理论(转)
1.以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加)
对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示10000000000000000每一位代表一个站点,每天放票前初始化到下面的订票表中,数据如下余票根据座位标识中的0的个数决定最大余票数量
订票表中的始发受限站点和终到受限站点可以灵活搭配(这个就可以实现限制站点发售)
限售渠道十进制 7 代表 1(车站)| 2(互联网)|4(电话)=7 即该票允许 车站, 互联网, 电话同时出售
那么还可以是 1|4 = 5 即该票只接受在车站和电话预定
扩展 8(代售点) 16 (手机端)
2.查询余票
如果我们要用互联网渠道查询日期为2016-06-11,始发站保定东站(3)到韶关站(15)的G71二等座F座位余票情况只需要执行如下sql(该SQL可以实现选座位和选车厢等功能)
![](https://yqfile.alicdn.com/img_51e409b11aa51c150090697429a953ed.gif)
select GUID,车次编码,车次类型,座位类型,车厢号码,座位编码,座位位置,车票版本号 from 订票表 where 座位标识=~((~坐标标识)|000111111111111000) and 发车日期='2016-06-11' and 车次编码='G71' and 始发受限车站=始发受限车站|000100000000000000 and 终到受限车站=终到受限车站|000000000000001000 and 车次类型='二等座' and 座位位置='F'and 受限渠道=2|受限渠道order by 余票数量 asc ,车厢 asc --先卖余票少的,防止打乱更多的长途票
![](https://yqfile.alicdn.com/img_51e409b11aa51c150090697429a953ed.gif)
3.预定票
3.1根据第二步中查询条件获取一条记录然后将车票状态改为锁定
3.2待锁定成功后进行支付
update 订票表 set 座位标识=座位标识 | 000111111111111000,车票版本号=车票版本号+1,余票数量 = 余票数量-(15-3)where GUID = Md5(车次+座位编码+发车日期) and 座位标识=~((~坐标标识)|000111111111111000)--乐观锁根据更新结果是否为1则可以判定购票成功
3.2支付成功后然后将保定到韶关的票保存到另外一张客户的车票表中
3.3如果指定时间没有支付,那么直接调用退票sql
4.退票
获得该车次保定到韶关的票 (000111111111111000)与对应的票进行异或^运算,则即可回归票池子了
5.选座
update 订票表 set 座位标识=座位标识 ^000111111111111000,余票数量 = 余票数量+(15-3),车票版本号=车票版本号+1 where GUID = Md5(车次+座位编码+发车日期) and 车票版本号=取得的版本号 --乐观锁
根据返回结果为1则标识退票成功
以下为相关java代码
![](https://yqfile.alicdn.com/img_51e409b11aa51c150090697429a953ed.gif)
1 import java.math.BigDecimal;2 3 public class MainTest {4 public static void main(String[] args) {5 String ticketFlag = "100000000000000000";6 int beginStation = 3;7 int endStation = 15;8 long beginTime = System.currentTimeMillis();9 String result = orderTicket(ticketFlag, beginStation, endStation);10 if (result.equals(ticketFlag)) {11 System.out.println("订票失败");12 } else {13 System.out.println("订票后的结果:" + result);14 // 如果要取消的话,就进行这个操作15 String b = buildTicket(ticketFlag.length(), beginStation,16 endStation);17 System.out.println("释放后的结果:" + releaseTicket(ticketFlag, b));18 19 }20 long endTime = System.currentTimeMillis();21 System.out.println("耗时:" + (endTime - beginTime));22 }23 24 /**25 * 订票26 * 27 * @param ticketFlag28 * @param beginStation29 * @param endStation30 * @return31 */32 private static String orderTicket(String ticketFlag, int beginStation,33 int endStation) {34 String result = "";35 if (checkCanTicket(ticketFlag, beginStation, endStation)) {36 String b = buildTicket(ticketFlag.length(), beginStation,37 endStation);38 39 String currentTicked = toTicket(ticketFlag, b);40 System.out.println("预占票前结果:" + ticketFlag);41 result = currentTicked;42 } else {43 result = ticketFlag;44 }45 ;46 return result;47 }48 49 /**50 * 取消已定票51 * 52 * @param ticketFlag53 * @param b54 * @return55 */56 private static String releaseTicket(String ticketFlag, String b) {57 StringBuilder tempSt = new StringBuilder("");58 int length = ticketFlag.length();59 for (int i = 0; i < length; i++) {60 char tempA = ticketFlag.charAt(i);61 char tempB = b.charAt(i);62 if (tempA == '1' && tempB == '1') {63 tempSt.append("0");64 } else {65 tempSt.append(tempA);66 }67 }68 return tempSt.toString();69 }70 71 /**72 * 创建区间占位票73 * 74 * @param length75 * @param beginStation76 * @param endStation77 * @return78 */79 private static String buildTicket(int length, int beginStation,80 int endStation) {81 StringBuilder st = new StringBuilder("");82 for (int i = 0; i < length; i++) {83 if (i >= beginStation && i < endStation) {84 st.append("1");85 } else {86 st.append("0");87 }88 }89 System.out.println("创建区间票:" + st.toString());90 return st.toString();91 }92 93 /**94 * 生成订票后的结果95 * 96 * @param ticketFlag97 * @param b98 * @return99 */ 100 private static String toTicket(String ticketFlag, String b) { 101 StringBuilder tempSt = new StringBuilder(""); 102 int length = ticketFlag.length(); 103 for (int i = 0; i < length; i++) { 104 char tempA = ticketFlag.charAt(i); 105 char tempB = b.charAt(i); 106 if (tempA == '1' || tempB == '1') { 107 tempSt.append("1"); 108 } else { 109 tempSt.append(tempA); 110 } 111 } 112 return tempSt.toString(); 113 } 114 115 /** 116 * 是否可以订票 117 * 118 * @param ticketFlag 119 * @param beginStation 120 * @param endStation 121 * @return 122 */ 123 private static boolean checkCanTicket(String ticketFlag, int beginStation, 124 int endStation) { 125 boolean result = false; 126 String tempTicket = ticketFlag.substring(beginStation, endStation); 127 BigDecimal b = new BigDecimal(tempTicket); 128 if (b.equals(new BigDecimal("0"))) { 129 result = true; 130 } 131 return result; 132 } 133 134 }
![](https://yqfile.alicdn.com/img_51e409b11aa51c150090697429a953ed.gif)
本文原创:转载请注明出处 http://www.cnblogs.com/feichengwurao/p/5191253.html
说一下本人的几点改进想法:
1.guid 可以用 车次+车厢+座位编码+始发时间+(后4位递增的尾数序列) 的联合编码来替换,作为 “行健”。
2. 设计的这张表是针对票的,那么就专注票本身建模就好,始发受限站点 和 终到受限站点 最好不要用 和售票逻辑耦合的二进制码作为字段,直接使用站点自己的编码更好。
3.实现本文,生成韶关后面的票的算法,大可简单粗暴一些。把车次经过的站再设计一张表,存每个站的站编码和站位一一对应关系。生成后半段的票的时候,直接从这个表里去查那些站该座还可以卖就好了。当然站点编码和站位的关系是静态数据,放到读多写少的缓存里查询更快一些。
4. 还有就是,这个新生成的票,最...
非常感谢@MarsLeno提供的改进想法
1.GUID本身就是Md5(车次+座位编码+发车日期)生成的,这样可以保证此票的唯一性,在高并发的情况下可以防止重复插入
2.设计这张表的并不是针对票的,而是针对售票整个业务,在大数据量的情况下可以避免多表交叉查询,提高查询效率,而受限字段只是便于进行查询的一种手段。
针对3,4,5 采用更新的手段,只是针对一条数据的更新操作,在大数据量的情况下更新的效率会比插入一条效率高很多
初探12306售票算法(一)- 理论(转)相关推荐
- 售票java代码_初探12306售票算法(二)-java代码实践
周五闲来无事,基于上一篇关于初探12306售票算法(一)-理论,进行了java编码实践供各位读者参考(以下为相关代码的简单描述) 1.订票工具类 1.1初始化一列车厢的票据信息 /** * 生成Tic ...
- 算法:初探12306售票算法。
以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加) 对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示10000000000 ...
- 初探12306售票算法
1.以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加) 对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示100000000 ...
- 票据ticket实现方式java代码_Java代码实践12306售票算法(二)
周五闲来无事,基于上一篇关于浅析12306售票算法(java版)理论,进行了java编码实践供各位读者参考(以下为相关代码的简单描述) 1.订票工具类 1.1初始化一列车厢的票据信息 /** * 生成 ...
- 售票java代码_Java代码实践12306售票算法(二)
周五闲来无事,基于上一篇关于浅析12306售票算法(java版)理论,进行了java编码实践供各位读者参考(以下为相关代码的简单描述) 1.订票工具类 1.1初始化一列车厢的票据信息 /** * 生成 ...
- java按顺序售票方法_java_Java代码实践12306售票算法(二),周五闲来无事,基于上一篇关 - phpStudy...
Java代码实践12306售票算法(二) 周五闲来无事,基于上一篇关于浅析12306售票算法(java版)理论,进行了java编码实践供各位读者参考(以下为相关代码的简单描述) 1.订票工具类 1.1 ...
- 车票购买最低消费问题java_浅析12306售票算法(java版)
1.以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加) 对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示100000000 ...
- java 火车算法_浅析12306售票算法(java版)
1.以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加) 对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示100000000 ...
- Zookeeper命令操作(初始Zookeeper、JavaAPI操作、分布式锁实现、模拟12306售票分布式锁、Zookeeper集群搭建、选举投票)
Zookeeper命令操作(初始Zookeeper.JavaAPI操作.分布式锁实现.模拟12306售票分布式锁.Zookeeper集群搭建.选举投票) 1.初始Zookeeper Zookeeper ...
最新文章
- 点击TableView任一行跳转详情页面会跳转两次的解决办法
- jackson (json、xml的序列化与反序列化)
- C#分隔字符串时遭遇空值
- 华为交换机一次性进入多个接口_华为交换机端口的批量配置命令
- C语言文件操作函数大全(看到总结的真的很好,就转载贡献给大家了)
- [译] 你是如何拆分组件的?
- fatal error C1083: Cannot open include file: 'iostream.h': No such file or dire
- 20172329 2017-2018-2 《程序设计与数据结构》第五周学习总结
- 计算机的k代表什么意思,电脑CPU后缀K、U、HQ、M分别代表什么你清楚吗?
- JavaWeb调用顺序
- office365中word打开时显示“word无法启动转换器RECOVR32.CNV”的解决办法
- 离线语音遥控器控制红外设备
- GPS与GPRS模块功差之千里
- glibc 知:手册06:字符集处理
- pxtorem插件配置
- 人类的心理行为模式----《影响力》中的心理学实验摘录(转)
- 计算机职称考试科目及内容,计算机职称考试科目有哪些?
- Spring整合MyBatis导致一级缓存失效问题
- ssm+redis缓存配置
- windows10驱动 x64--- 3环代码加载驱动(二)
热门文章
- 中国所有城市(json数据)
- @Autowired 与@Resource的区别(详细)
- 鼠标光标是黑色方块,切换为竖线的方法
- 二维数组的foreach遍历和三种集合的遍历
- Samtec连接器科普| 您所在的环境对电子设备来说,苛刻吗
- BCC(Borland C++ Compiler)编译 ISAPI 扩展或者用MinGW也行
- Python练习100题,建议收藏
- WEKA使用(基础配置+垃圾邮件过滤+聚类分析+关联挖掘)
- cakephp分页/cakephpページング/cakephp paging
- 2021年全球高温过滤介质收入大约2462.3百万美元,预计2028年达到4075.6百万美元