日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

12306 出票的一种算法设计

發布時間:2024/1/18 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 12306 出票的一种算法设计 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
引子

12306 一度成為技術圈的評論熱點,期間被鄙視過, 也被理解過。在我 2.5 年的技術生涯中, 至少 讀到過 8 篇關于 12306 的文章,當然,最早的文章是罵 12306 的。今年的春節也不出意外讀到了關于 12306 的文章,當然是對 12306 的理解與包容,甚至是贊美。前面兩個春節讀到 12306 的文章并沒有 引發我的思考,而這個春節,可能由于我將近 1 個月未上班的原因,我倒是認真思考起 12306 的業務 模型,進而在頭腦中有了這個初步設計。

本文的目的不是對 12306 作評價,而是基于本人對 12306 業務的理解,自己重新實現一套 12306 的系統設計。 本人對自己的這個設計方案比較滿意,認為該方案可以很好的解決 12306 的性能瓶頸。


免噴聲明

  • 由于本人不是 12306 的工作人員,對鐵道部的運行方案不是很了解,難免有些分析不當的地方,請專業人士批判指出,請圈外人士勿噴。

  • 本人對自己的文字表達能力相當有懷疑, 如有疑問, 歡迎交流。

  • 設計步驟
  • 業務的抽象與提取

  • 數據結構,算法的設計

  • 數據庫設計


  • 設計容易犯的錯誤

    我們容易忽略 1 步驟,交換 2,3 步驟, 也是設計思路是變成了:

  • 數據庫設計

  • 算法設計(數據結構被數據庫決定了)

  • 業務抽象和提取

    以后詳細描述, 現在簡單提取

    Nothing but Motto: 交流的時候統一語言,計算的時候統一量綱。

    業務流程

  • 用戶輸入起點站,終點站,選擇日期

  • 根據輸入找到相應的班次

  • 查詢每個班次的剩余票數

  • 用戶點擊購買,填寫乘客人信息

  • 根據起點站,終點站和日期分配票

  • 準備出票:

    • 用戶支付成功,出票

    • 用戶超時,票回收(回滾操作)


    提取

  • 系統的核心功能是查票,購票。票作為我們的商品, 我們需要根據具體情況來定義票的概念,合理化票的量綱。

  • 火車票的最小單位是:1(座位)* 1(個站區間), 我們約定這個最小單位是?ticket?。后續提到?票?都是指用戶購買的票(n 個?ticket?構造而成)。

  • 對于有座位的票,要統一票 id(反正我坐火車從來沒有中途被要求換個位置)。對于這一點, 解決還是比較方便的, 對于同一座位, 放入一個票池子, 同時限制一張車票,只能從同一個池子里面去。

  • 對于無座位的票, 統一放入一個票池子,或者分車廂放入幾個票池子。

  • 站票的最小單位是:1(個站區間),由于站票的無固定位置特性,站票的最小單位和座位票有區別,因此站票的數據應該跟著列車的站點走。


  • 抽象

    根據上述定義,我們可以構造一張?tickets?表,座位號為行,站區間為列。假設列車經過 ABCDEFG 7 個站點,上面有 5 個座位號,那么?tickets?表為(先忽略站票):


    實例

    火車經過 ABCDEFG 7 個站點, 小王買了一張 B 到 D 的票。

  • 小王買了幾張?ticket??

    答:2 張,分別為?BC?和?CD?區間的?ticket?。

  • 假設小王買的票是 2 號座位, 請標記相關?ticket?。

    答: 如下圖:

  • 下圖出票方式是否合理?

    答: 不合理,其中紅色的票使得?tickets?池碎片化。 后續只能出 2 張全程票(A?G)。 如果紅色的票分配到 1 號座位,后續還可以出 3 張全程票,可使收益最大化,12306 也是要賺錢的了。

    那這樣是不是會使得位置特別不均勻呢?確實是的,坐過火車的人會注意到這點的。不過這 并不是什么問題,大家總是會自動向座位空空的地方移。但實際上,這根本不是問題, 這圖上的位置不過是?邏輯位置?而已,把它跟實際?物理位置?做個映射就行。 學過計算機的人都知道內存有?邏輯地址?和?物理地址?的概念,他們有個映射關系。

    綜上所述:出票分配位置時應該從上向下遍歷,找到第一個可用的。

  • 數據結構和算法的設計

    這里不討論我對有關設計的演進了,直接指出最終設計。


    tickets 數據結構

    我們觀察上述圖片的時候,有沒有想過 白色區域代表 1, 著色區域代表 0, 就可以得到一個內存圖。每個座位對應的行用一個?int64?就可以代替了(我們假設列車最多經過 65 個站點,這個假設應該是合理的,假設不正確也沒關系, 不影響我們的算法)。


    查詢

    假設小王要查詢 B?D 的票,占據第 2 和第 3 個區間。 我們只需要構建位置值 (后續稱ticket_value) 6, 分別和每一個位置的值做?位與?運算,如果結果為 6, 說明位置可用, 遍歷一遍, 就可以得到剩余位置數。


    購買

    假設小王要購買 B?D 的票,從可分配的位置里面選取第一個減去?

    程序系統設計


    數據庫系統設計

  • trains

    id

    code

    type




    7

    G77

    高鐵

    8

    D63

    動車

  • sites

    id

    name



    1

    上海

    2

    濟南

    3

    北京

  • site_train_xRef

    site_id

    train_id

    site_nth

    n_sro





    1

    7

    0

    3

    2

    7

    7

    3

    3

    7

    9

    3

    • site_nth 為 0 代表始發站。

    • n_sro 為站票剩余數目,跟著列車的站點走。

    tickets

    id

    pos_id

    n_remain




    1

    1A

    int_max

    1

    3F

    int_max

    • 建議為每一輛列車建立一個?tickets?表, 這樣也很容易分配到不同的機器上去查詢。也可以在 tickets 中加入一個?train_id?字段。


    查票步驟

  • 根據?site_train_xRef?找到符合要求的的列車班次。

  • 分別各列車計算出票值?ticket_value?。

  • 分別在找出的班次中檢索余票, 判斷該座位可用:?(n_remain & ticket_value) = ticket_value?。


  • 鎖定票

    用戶購買,生成訂單后,鎖定票。

    • 解釋步驟不如直接上代碼:+

    ?update tickets set n_remain = n_remain - ticket_value ?where id in(select id from tickets ? ? where n_remain & ticket_value = ticket_valueorder by idlimit 1);

    和公司 CTO 討論一下后發現上述 sql 不是個好方法:

  • 上述語句的原子性不清楚,如果不是原子性, 那就是 bug 了。

  • 如果上述 sql 是原子性的, 上述原子操作鎖的粒度比較大, 性能有問題。

  • 我們得出方案, 改成兩步操作, 第二步如果失敗, 就重試:

    ?select id as oid from tickets ? ? ? where n_remain & ticket_value = ticket_valueorder by idlimit 1;update tickets set n_remain = n_remain - ticket_value ? ?where id = oid and n_remain & ticket_value = ticket_value;

    其他業務場景暫時交給讀者們了

    結語
    • 本人僅僅給出了出票算法一種設計而已, 離實用性還差很遠,鐵道部的具體賣票措施也不知道。比如說會有站點限制什么的。

    總結

    以上是生活随笔為你收集整理的12306 出票的一种算法设计的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。