1. 程式人生 > >[python]My Unique JsonDiff演算法——如何計算2個json串之間的差距並Diff出來(一):編輯距離(Levenshtein)演算法

[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]  


 應該還有其他不同的方法來優化這個演算法的實現~~歡迎探討~~