初探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  座位標識=~((~坐標標識)|000111111111111000and 發車日期='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)--樂觀鎖

        根據更新結果是否為1則可以判定購票成功

 

  3.2支付成功后然后將保定到韶關的票保存到另外一張客戶的車票表中

  3.3如果指定時間沒有支付,那么直接調用退票sql

4.退票

  獲得該車次保定到韶關的票 (000111111111111000)與對應的票進行異或^運算,則即可回歸票池子了

5.選座

       

update 訂票表 set 座位標識=座位標識 ^000111111111111000,余票數量 = 余票數量+(15-3),車票版本號=車票版本號+1 where GUID = Md5(車次+座位編碼+發車日期)  and 車票版本號=取得的版本號 --樂觀鎖
 根據返回結果為1則標識退票成功

 

以下為相關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 }

 

 

 

本文原創:轉載請注明出處 http://www.cnblogs.com/feichengwurao/p/5191253.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM