Lua-table.sort的error分析

問題描述

lua table.sort 排序報錯,invalid order function for sorting stack traceback

測試代碼

在這裏插入圖片描述在這裏插入圖片描述

結論

根據測試結果,出現lua error需要滿足以下條件

  • table中元素數量大於3
  • table中元素存在相等情況
  • 當元素相等時,排序方法返回true
  • 排序算法不穩定

源碼分析

不穩定的算法不一定會報錯,所以在複雜排序算法上很容易出現偶現bug。期根本原因是算法不穩定。

a = t0[1] =40 b=t0[3]=40 和 a = t0[3] =40 b=t0[1]=40情況下返回不同的值。

快速排序原本是不穩定的排序方法,對算法本身來說返回true,false無關緊要,不論2個值是否交換位置,對排序結構沒有任何問題。lua error的產生與算法的實現代碼有關。

lua 5.1(5.3代碼和5.1略有不同,不過算法本身並無改動)
static void auxsort (lua_State *L, int l, int u) {
  while (l < u) {  /* for tail recursion */
    int i, j;
    /* sort elements a[l], a[(l+u)/2] and a[u] */
    lua_rawgeti(L, 1, l);
    lua_rawgeti(L, 1, u);
    if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */
      set2(L, l, u);  /* swap a[l] - a[u] */
    else
      lua_pop(L, 2);
    if (u-l == 1) break;  /* only 2 elements */
    i = (l+u)/2;
    lua_rawgeti(L, 1, i);
    lua_rawgeti(L, 1, l);
    if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */
      set2(L, i, l);
    else {
      lua_pop(L, 1);  /* remove a[l] */
      lua_rawgeti(L, 1, u);
      if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */
        set2(L, i, u);
      else
        lua_pop(L, 2);
    }
    if (u-l == 2) break;  /* only 3 elements */
    lua_rawgeti(L, 1, i);  /* Pivot */
    lua_pushvalue(L, -1);
    lua_rawgeti(L, 1, u-1);
    set2(L, i, u-1);
    /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
    i = l; j = u-1;
    for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */
      /* repeat ++i until a[i] >= P */
      while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
        if (i>u) luaL_error(L, "invalid order function for sorting");
        lua_pop(L, 1);  /* remove a[i] */
      }
      /* repeat --j until a[j] <= P */
      while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
        if (j<l) luaL_error(L, "invalid order function for sorting");
        lua_pop(L, 1);  /* remove a[j] */
      }
      if (j<i) {
        lua_pop(L, 3);  /* pop pivot, a[i], a[j] */
        break;
      }
      set2(L, i, j);
    }
    lua_rawgeti(L, 1, u-1);
    lua_rawgeti(L, 1, i);
    set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */
    /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
    /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
    if (i-l < u-i) {
      j=l; i=i-1; l=i+2;
    }
    else {
      j=i+1; i=u; u=j-2;
    }
    auxsort(L, j, i);  /* call recursively the smaller one */
  }  /* repeat the routine for the larger one */
}

對於小於4個元素的排序,根本沒有使用快速排序算法。而是直接進行了比較。

  	while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
        if (i>u) luaL_error(L, "invalid order function for sorting");
        lua_pop(L, 1);  /* remove a[i] */
      }

當wile循環中如果sort_comp一直返回true那麼必定會超出範圍,出現報錯。所以偶現error其實是特殊的序列+不穩定算法(return true)倒是的問題。

使用建議

建議:
1、使用排序規則明確,穩定的sort_comp
2、慎重使用 return true
3、不要使用return a>=b 或者 return a <=b
4、確保 a==b 返回 false

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章