Lua 自己實現排序sort比較方法,拋出錯誤invalid order function for sorting


明天新功能就要上了,結果剛剛突然QA說項目拋出了錯誤。握草,嚇得立馬出了一身汗。

查了一下錯誤,發現可能是自己寫的不穩定排序造成的。自己感覺應該就是。把排序方法寫成穩定的之后,代碼分離編譯進手機,跑了一下木有錯誤了。腦殘的自己為何要對服務器傳過來的有序數據進行排序呢?腦抽不明。

下文為轉的別人總結的lua庫。(該學習的地方還太多)

lua的table庫

 

函數列表: 
table.insert(table,[ pos,] value) 
table.remove(table[, pos]) 
table.concat(table[, sep[, i[, j]]]) 
table.sort(table[, comp])



1. insert 和 remove 只能用於數組元素的插入和移出, 進行插入和移出時,會將后面的元素對齊起來。 
    所以在 for 循環中進行 insert 和 remove 的時候要注意插入和移除時是否漏掉了某些項: 
        local t = {1,2,3,3,5,3,6} 
        for i,v in ipairs(t) do 
            if v == 3 then 
                table.remove(t,i) 
            end 
        end 
        -- 錯誤,第四個 3 沒有被移除,ipairs 內部會維護一個變量記錄遍歷的位置,remove 掉第三個數字 3 之后,ipairs 下一個返回的值是 5 而不是 3 
        
        local t = {1,2,3,3,5,3,6} 
        for i=1, #t do 
            if t[i] == 3 then 
                table.remove(t,i) 
                i = i-1 
            end 
        end 
        -- 錯誤,i=i-1 這段代碼沒有用,i 的值始終是從 1 到 #t,for 循環里修改 i 的值不起作用 
        
        local t = {1,2,3,3,5,3,6} 
        for i=#t, 1, -1 do 
            if t[i] == 3 then 
                table.remove(t,i) 
            end 
        end 
        -- 正確,從后往前遍歷 
        
        local t = {1,2,3,3,5,3,6} 
        local i = 1 
        while t[i] do 
            if t[i] == 3 then 
                table.remove(t,i) 
            else 
                i = i+1 
            end 
        end 
        -- 正確,自己控制 i 的值是否增加 
     


   
2. concat 可以將 table 的數組部分拼接成一個字符串,中間用 seq 分隔。 
    lua 中字符串的存儲方式與 C 不一樣,lua 中的每個字符串都是單獨的一個拷貝,拼接兩個字符串會產生一個新的拷貝,如果拼接操作特別多,就會影響性能: 
        local beginTime = os.clock() 
        local str = "" 
        for i=1, 30000 do 
            str = str .. i 
        end 
        local endTime = os.clock() 
        print(endTime - beginTime) 
        -- 消耗 0.613 秒,產生了 30000 個字符串拷貝,但只有最后一個是有用的

        local beginTime = os.clock() 
        local t = {} 
        for i=1, 30000 do 
            t[i] = i 
        end 
        local str = table.concat(t, "") 
        local endTime = os.clock() 
        print(endTime - beginTime) 
        -- 消耗 0.024 秒,利用 concat,一次性把字符串拼接出來,只產生了一個字符串拷貝 
       



3. sort 可以將 table 數組部分的元素進行排序,需要提供 comp 函數,comp(a, b) 如果 a 應該排到 b 前面,則 comp 要返回 true 。    
    注意,對於 a==b 的情況,一定要返回 false : 
        local function comp(a,b) 
            return a <= b 
        end 
        table.sort(t,comp) 
        -- 錯誤,可能出現異常:attempt to compare number with nil 
        
        local function comp(a,b) 
            if a == nil or b == nil then 
                return false 
            end 
            return a <= b 
        end 
        table.sort(t,comp) 
        -- 錯誤,可能出現異常:invalid order function for sorting 
        -- 也可能不報這個異常,但結果是錯誤的; 
    之所以 a==b 返回true 會引發這些問題,是因為 table.sort 在實現快速排序時沒有做邊界檢測: 
        for (;;) { 
          while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {  // 未檢測邊界, i 會一直增加 
            if (i>=u) luaL_error(L, "invalid order function for sorting"); 
            lua_pop(L, 1); 
          } 
          while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {  // 未檢測邊界, j 會一直減少 
            if (j<=l) luaL_error(L, "invalid order function for sorting"); 
            lua_pop(L, 1); 
          } 
          if (j<i) { 
            lua_pop(L, 3); 
            break; 
          } 
          set2(L, i, j); 
        } 
    看以上代碼,如果 a==b 時返回 true 且邊界上的幾個值是相等的話, sort_comp 就無法阻止 i 繼續增長,直到超出邊界引發異常 attempt to compare number with nil;即使我們對 a 和 b 進行非空判斷,也會因為 i 超過邊界而引發異常 invalid order function for sorting 
    快速排序是什么,lua 如何實現快速排序,可以參考 lua 源碼中的描述,這里不多介紹; 

 

 

---------------------------------------------

所以代碼可以寫成

  local function comp(a,b) 
            if a == nil or b == nil then 
                return false 
            end 
            if a == b then
         return false
    end
            return a < b
  end 
  table.sort(t,comp) 

意思就是,在a == b 時,不進行交換就可以了。交換的話,就會導致不穩定。

   


免責聲明!

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



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