初探12306售票算法(一)-理论
初探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可以实现选座位和选车厢等功能)
select GUID,车次编码,车次类型,座位类型,车厢号码,座位编码,座位位置,车票版本号from订票表
where座位标识=~((~坐标标识)|000111111111111000)
and发车⽇期='2016-06-11'
and车次编码='G71'
and始发受限车站=始发受限车站|000100000000000000
and终到受限车站=终到受限车站|000000000000001000
and车次类型='⼆等座'
and座位位置='F'
and 受限渠道=2|受限渠道
order by 余票数量 asc ,车厢 asc  --先卖余票少的,防⽌打乱更多的长途票
3.预定票
3.1根据第⼆步中查询条件获取⼀条记录然后将车票状态改为锁定
3.2待锁定成功后进⾏⽀付
update订票表set座位标识=座位标识 | 000111111111111000,车票版本号=车票版本号+1,余票数量 = 余票数量-(15-3)
where GUID = Md5(车次+座位编码+发车⽇期) and座位标识=~((~坐标标识)|000111111111111000)--乐观锁
12306几点开始放新一天的预订票
根据更新结果是否为1则可以判定购票成功
3.2⽀付成功后然后将保定到韶关的票保存到另外⼀张客户的车票表中
3.3如果指定时间没有⽀付,那么直接调⽤退票sql
4.退票
获得该车次保定到韶关的票(000111111111111000)与对应的票进⾏异或^运算,则即可回归票池⼦了
5.选座
update订票表set座位标识=座位标识 ^000111111111111000,余票数量 = 余票数量+(15-3),车票版本号=车票版本号+1where GUID = Md5(车次+座位编码+发车⽇期)  and 车票版本号=取得的版本号--乐观锁根据返回结果为1则标识退票成功
以下为相关java代码
1import java.math.BigDecimal;
2
3public class MainTest {
4public static void main(String[] args) {
5        String ticketFlag = "100000000000000000";
6int beginStation = 3;
7int endStation = 15;
8long beginTime = System.currentTimeMillis();
9        String result = orderTicket(ticketFlag, beginStation, endStation);
10if (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        }
20long 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*/
32private static String orderTicket(String ticketFlag, int beginStation,
33int endStation) {
34        String result = "";
35if (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        ;
46return result;
47    }
48
49/**
50    * 取消已定票
51    *
52    * @param ticketFlag
53    * @param b
54    * @return
55*/
56private static String releaseTicket(String ticketFlag, String b) {
57        StringBuilder tempSt = new StringBuilder("");
58int length = ticketFlag.length();
59for (int i = 0; i < length; i++) {
60char tempA = ticketFlag.charAt(i);
61char tempB = b.charAt(i);
62if (tempA == '1' && tempB == '1') {
63                tempSt.append("0");
64            } else {
65                tempSt.append(tempA);
66            }
67        }
String();
69    }
70
71/**
72    * 创建区间占位票
73    *
74    * @param length
75    * @param beginStation
76    * @param endStation
77    * @return
78*/
79private static String buildTicket(int length, int beginStation,
80int endStation) {
81        StringBuilder st = new StringBuilder("");
82for (int i = 0; i < length; i++) {
83if (i >= beginStation && i < endStation) {
84                st.append("1");
85            } else {
86                st.append("0");
87            }
88        }
89        System.out.println("创建区间票:" + st.toString());
String();
91    }
92
93/**
94    * ⽣成订票后的结果
95    *
96    * @param ticketFlag
97    * @param b
98    * @return
99*/
100private static String toTicket(String ticketFlag, String b) {
101        StringBuilder tempSt = new StringBuilder("");
102int length = ticketFlag.length();
103for (int i = 0; i < length; i++) {
104char tempA = ticketFlag.charAt(i);
105char tempB = b.charAt(i);
106if (tempA == '1' || tempB == '1') {
107                tempSt.append("1");
108            } else {
109                tempSt.append(tempA);
110            }
111        }
String();
113    }
114
115/**
116    * 是否可以订票
117    *
118    * @param ticketFlag
119    * @param beginStation
120    * @param endStation
121    * @return
122*/
123private static boolean checkCanTicket(String ticketFlag, int beginStation, 124int endStation) {
125boolean result = false;
126        String tempTicket = ticketFlag.substring(beginStation, endStation); 127        BigDecimal b = new BigDecimal(tempTicket);
128if (b.equals(new BigDecimal("0"))) {
129            result = true;
130        }
131return result;
132    }
133
134 }

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