lua排序函数(table.sort)报错浅析————invalid order function for sorting

table.sort 概述

  1. table.sort函数的本质是快排算法,在此基础上做了三点优化
  2. 每次分割数组的锚点是从当前分割数组的初始点、中间点、结尾点中选择中位数作为锚点,减少极端情况下快排的次数每次分割数组的锚点是从当前分割数组的初始点、中间点、结尾点中选择中位数作为锚点,减少极端情况下快排的次数
  3. 对于迭代函数中的分割数组长度小于等于3的,直接通过比较大小交换位置,形成有序数组,这样做的目的是减少递归调用的深度
  4. 每次通过锚点把分割数组分成两半之后,对长度较小的一半进行递归调用,另一半则继续通过While继续分割处理,目的应该也是减少递归调用的深度

table.sort源码及注释

    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);
    
        //上面代码是对分割数组长度小于等于3的进行比较和排序
        //并从数组初始点、中间点、结尾点中选择中位数作为锚点
    
        /* 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 */
      
        //上面代码是让分割后长度较短的数组继续迭代,长度较长的则继续通过while进行快排算法,减少递归调用的次数
    }

invalid order function for sorting报错的原因及解决方法

     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] */
     }

在源码中可以看到报错的位置。当锚点的值与边界值相等,这时如果排序方法sort_comp返回true,则会造成数组越界,而解决方案也很简单——当比较的两个值相等时,返回false即可。

个人认为较好的lua排序函数写法

假设战力排行榜有战力,等级两个排序因子,要求先按战力从高往低排,再按等级从高往低排,那么排序函数可以这么写。

    table.sort(战力排行榜, function(a, b)
        if a.战力 ~= b.战力 then
            return a.战力 > b.战力
        end
        if a.等级 ~= b.等级 then
            return a.等级 > b.等级
        end
        return false
    end)

ps:上文提及lua版本是 5.1

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值