短網址,我想你們應該都見過,若是沒有,試着點擊下面這條連接 https://git.io/vSY4o,會跳到個人 GitHub 主頁,可是它確實比原始連接 https://github.com/hanzichi 要短了一些。關於短網址的做用,這裏不做描述,本文主要講講如何實現一個簡單的短網址系統。javascript
Leetcode 正好 有一題 與此有關,不妨一試。html
若是沒有接觸太短網址,不妨去 https://goo.gl/ 和 https://git.io/ 稍微體驗下。體驗的結果是,短網址都把網址壓縮成了六個字符,這是巧合嗎?java
短網址整個運轉邏輯很是簡單,咱們以 https://goo.gl/SfzlA2 爲例,當咱們訪問這個網址的時候,後端能夠獲取 "SfzlA2" 這個字符串,而後跳轉到 https://github.com/hanzichi,很顯然,這個字符串和這個地址已經綁定,經過某種映射關係能夠從 "SfzlA2" 獲取完整的地址。git
那麼,看起來咱們只須要找到一個算法,可以將一個長字符串壓縮成一個短的字符串,而且該算法應該是可逆的。可是實現這樣的文本壓縮算法,是很是困難的(不存在?),若是真有這麼一個算法和逆運算,那麼基本上如今的壓縮軟件均可以歇菜了,而世界上全部的信息(網址長度未知),均可以壓縮成固定長度個字符,這可能嗎?因此不要幻想使用壓縮算法,並且對於 URL 這種不超過 100 bytes 的字符串,壓縮算法的壓縮比一般都大於 1。github
因此咱們應該轉變思路。目前流行的短網址算法大概有兩種,一種是利用 md5,將長網址 md5 後,再進行分組壓縮,由於 md5 實質上是一種哈希算法,因此不免出現碰撞,固然,咱們有解決哈希衝突的 N 種方法,可是這隻會增長系統的複雜度,不推薦。另一種是將網址和一個 62 進制數(0-9 & a-Z)對應,存入數據庫中,須要的時候,經過數據庫查詢提取。算法
接着咱們就根據以上的思路,來實現一個簡單的短網址系統。數據庫
咱們先不考慮 62 進制的轉換,用 Map 來當作一個 k-v 的數據庫。當存入第一個網址的時候,假設咱們的短網址是 xx.com/0,能夠將 0 當作 key,將實際網址當作 value,須要查詢的時候直接提取,若是有新的短網址須要生成,將 key 自增。代碼以下。後端
let [p, index] = [new Map(), 0]; /** * Encodes a URL to a shortened URL. * * @param {string} longUrl * @return {string} */ var encode = function(longUrl) { p.set(index, longUrl); return index++; }; /** * Decodes a shortened URL to its original URL. * * @param {string} shortUrl * @return {string} */ var decode = function(shortUrl) { return p.get(shortUrl); };
很顯然,用一個 62 進制數表示,短網址能夠更短。咱們能夠本身實現一個簡單的 10 進制到 62 進制的轉換算法。緩存
let [p, index] = [new Map(), 0]; var base62 = (n) => { let str = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; let len = str.length; let ret = ''; do { ret += str[n % len]; n = ~~(n / len); } while (n); return ret; }; /** * Encodes a URL to a shortened URL. * * @param {string} longUrl * @return {string} */ var encode = function(longUrl) { let shortUrl = base62(index++); p.set(shortUrl, longUrl); return shortUrl; }; /** * Decodes a shortened URL to its original URL. * * @param {string} shortUrl * @return {string} */ var decode = function(shortUrl) { return p.get(shortUrl); };
這樣實現的話實際的短網址的數量實際上是受限的,理論上應該是(JavaScript)能表示的最大的整數。url
這樣的實現,還有一些其餘的問題,好比短網址的長度並非固定的,這點容易解決,補位便可。再好比,這些短網址,按照順序排列,並不顯得隨機,這也好辦,好比能夠隨機生成六位字符串看成 key,而不是用整數的遞增,這樣的話,短網址數量也不受限了(能夠增長短網址位數)。還有一點,相同的 URL 可能獲得不一樣的短網址,這點能夠另外加個哈希或者用 Set 去解決,還能夠加個緩存來解決(在緩存時間內,重定向到相同地址,一旦緩存失效,從新分配 key)。
除了算法設計外,真正的系統還須要考慮不少,好比發號器的設計,好比緩存(掛個 Redis),好比跳轉,等等,本文只是拋磚引玉,這些就留給大家本身去思考了。
短網址系統的設計,其實依賴的並非文本壓縮算法。有些時候,須要換個角度思考問題。