初探12306售票算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初探12306售票算法相关的知识,希望对你有一定的参考价值。

 1.以G71列车为例,首先对车次站台进行占位编码(从1开始到最后一站递加)

       技术分享

   对以上占位简单描述以下:G71总共18个站点那么我们的单个座位的座位标识可以用十八位长度的二进制字符串表示10000000000000000每一位代表一个站点,每天放票前初始化到下面的订票表中,数据如下

技术分享

 订票表中的始发受限站点和终到受限站点可以灵活搭配(这个就可以实现限制站点发售)

2.查询余票

如果我们要查询日期为2016-06-11,始发站保定东站(3)到韶关站(15)的G71二等座F座位余票情况只需要执行如下sql(该SQL可以实现选座位和选车厢等功能)

select GUID,车次编码,车次类型,座位类型,车厢号码,座位编码,座位位置 from 订票表

where  to_number(substring(座位标识,3,15))=0

and 发车日期=‘2016-06-11‘

and 车次编码=‘G71‘

and substring(始发受限车站,3,4)=1

and substring(终到受限车站,15,16)=1

and 车票状态=‘待售‘

and 车次类型=‘二等座‘

and 座位位置=‘F‘

3.预定票

  3.1根据第二步中查询条件获取一条记录然后将车票状态改为锁定

  3.2待锁定成功后进行支付

  3.2支付成功后然后将保定到韶关的票(000111111111111000这里的始发站标记为0)与原有的票进行与运算,并将车票状态改为待售

  3.3如果指定时间没有支付,那么可以将这条记录的车票状态恢复为待售

4.退票

  获得该车次保定到韶关的票 (000111111111111000)与对应的票进行非运算,则即可回归票池子了

 

以下为相关java代码 

 

  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 ticketFlag
 28      * @param beginStation
 29      * @param endStation
 30      * @return
 31      */
 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 ticketFlag
 53      * @param b
 54      * @return
 55      */
 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 length
 75      * @param beginStation
 76      * @param endStation
 77      * @return
 78      */
 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 ticketFlag
 97      * @param b
 98      * @return
 99      */
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 }

 技术分享

以上是关于初探12306售票算法的主要内容,如果未能解决你的问题,请参考以下文章

12306 售票网站新版验证码识别对抗

转--《浅谈12306核心模型设计思路和架构设计 》

Zookeeper -- Zookeeper JavaAPI相关操作(Curator介绍Curator API 常用操作(节点的CRUD,Watch事件监听)分布式锁模拟12306售票案例)

企业应如何解决网站流量暴增问题?

高峰,来了!

实验1