[python]My Unique JsonDiff演算法——如何計算2個json串之間的差距並Diff出來(一):編輯距離(Levenshtein)演算法
啊啊,年底忙著簽證什麼的,好久沒寫日誌啦。。。。新年到來,整點乾貨出來給大家~~順便為自己考試和申請學校攢點人品~~
之前實習的時候,因為實習公司的業務需求,需要一個比對json字串差異的演算法,然而我在網上查了很久的資料,發現竟然沒有現成的jsondiff演算法。。。殘念了很久之後,只能自己動手研究一種演算法用來比對json字串差異啦。。。我會在接下來的文章中,慢慢將整個jsondiff演算法的思路展開的。
jsondiff的演算法實質上就是對於特殊結構字串的一種比對演算法,因此首先引入的是最基礎的字串比對演算法之一:編輯距離演算法(又稱Levenshtein演算法)。編輯距離指的是兩個字串之間,由一個轉換成另一個所需的最少編輯操作次數。通常這裡的編輯操作是指替換、插入和刪除操作,即將一個字元替換成另一個字元、插入一個字元或者刪除一個字元。
舉個例子,假如我們想要使"sina.com“這個字串變成“sina.cn”,那麼最簡單的方法就是刪去"o",然後將"m"替換為"n"即可,這裡進行了2次編輯操作,即編輯距離為2。
而Levenshtein演算法就是用於計算這種編輯距離的一種常見演算法,其核心思想採用的是動態規劃。
這裡給出核心公式,我們根據這個公式從上到下構造矩陣就可以啦。
(至於什麼是動態規劃。。。咳咳,不懂的回去重新上一下資料結構跟演算法課去。。。。。)
下面給出程式碼,並不是太複雜的程式碼,出於便於除錯和檢驗的目的,我用python擼出來的:
#coding:utf8 def levenshtein(source, target): """ ditstance(source, target)->int return the levenshtein ditstance src_length = len(source)+1 tgt_length = len(target)+1 if src_length == 1: return tgt_length - 1 if tgt_length == 1: return src_length - 1 matrix = [range(tgt_length)] for i in range(1, src_length): row = [0]*tgt_length row[0] = i matrix.append(row) for i in range(1, src_length): src_char = source[i-1] for j in range(1, tgt_length): tgt_char = target[j-1] cost = 0 if src_char == tgt_char else 1 above = matrix[i-1][j]+1 left = matrix[i][j-1]+1 diag = matrix[i-1][j-1]+cost value = min(above, left, diag) matrix[i][j]=value return matrix[src_length-1][tgt_length-1]</span>
該演算法的時間複雜度是O(m*n),其中m、n分別為兩個字串的長度,而空間複雜度也是O(m*n),當然,細心的朋友可以看出來,一旦用於比對的2個字串長度較大,就會構造出佔用記憶體一個非常非常非常大的陣列,執行起來會非常坑爹的。所以我們完全可以在給出的程式碼基礎上進行優化,比如使用兩個列向量來替代矩陣,避免不必要的記憶體開銷:
def improvedEditdis(source,target): src_length, tgt_length = len(source), len(target) src_size, v1, v2 = src_length + 1, [], [] for i in range((tgt_length + 1)): v1.append(i) v2.append(i) for i in range(src_length + 1)[1:src_length + 1]: for j in range(tgt_length + 1)[1:tgt_length + 1]: cost = 0 if source[i - 1] == target[j - 1]: cost = 0 else: cost = 1 minValue = v1[j] + 1 if minValue > v2[j - 1] + 1: minValue = v2[j - 1] + 1 if minValue > v1[j - 1] + cost: minValue = v1[j - 1] + cost v2[j] = minValue for j in range(tgt_length + 1): v1[j] = v2[j] return v2[tgt_length]
應該還有其他不同的方法來優化這個演算法的實現~~歡迎探討~~