lua table.sort方法
- 排序出现报错
- 排序顺序不正确的现象
报错
1 | invalid order function for sorting |
出现了一次报错,但是在测试过程中没有复现,之后项目中出现了相同报错导致场景打不开。
顺序不正确
例子(功能:对一系列名称进行排序):
1 |
|
问题原因
感谢冥王星在WT中留了table.sort的使用问题
对于同样的输入,加不加等号结果不正确和正确之分
查问题原因
在每次比较中加打印,发现有等号的比较次数多,而且出现了一次b7和b7的比较
我们的排序表中没有连个b7,但是这里出现了b7和b7的比较
打印每次比较后表中的顺序,将出错的过程缩到下面的范围
1 | local markersname = { |
提取简单排序,从自定义的字符串比较中分出来
1 | local tb = {8, 2, 3, 1, 7} |
正确的比较过程和错误的比较过程对比如下:
查网上的table排序使用的方法是快排,用常见快排过程分析失败
看lua源码(5.3.5)中的sort方法
1 | static IdxT partition (lua_State *L, IdxT lo, IdxT up) { |
7和7比较后就会报错,与实际现象不符合
网上看到这个报错贴出来的源码和上面的不同,所以搜引擎中的lua库的.h文件,显示5.1.5
然后看lua源码(5.1.5)中的sort方法
1 | /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ |
这里可以看到它不是通过i、j的值控制是否停止比较,而是一直进行++和–操作,靠比较函数来判断是否停止比较
因而会因为 i 超过边界而引发异常 invalid order function for sorting,或者发生排序出现错误的情况
首先是排序出现不正确的地方,7和7比较之后,8和7又做了一次比较,87交换,后续都出了问题
如果这个地方是7和7比较,那么就会超过边界,抛出错误
首先看{8, 2, 3, 1, 7}
发生排序顺序不正确的情况
排序过程:
8 3 7排序,
{3, 2, 7, 1, 8}
中间值作为哨兵,并放在倒数第二位(up - 1),
{3, 2, 1, 7, 8}
从左到右++i与哨兵比较
{3, 2, 1, 7, 8}
i从1到4,这时7和7比较,应该返回false,i = 4,这里返回了true,所以继续比较,i = 5
从右(up - 2)到左–j与哨兵比较
{3, 2, 1, 7, 8}
7与1比较,不满足,所以 j = 3
j < i,停止比较
把哨兵放到它该在的位置上
swap pivot (a[u-1]) with a[i]
,出错,算法中按照i的位置来判断它该交换的位置,应该7和7交换,这里8和7交换之后
i - low = 4 < up - i = 0
不成立(6, 5)小区间递归排序
(1, 4)大区间循环排序
{3, 2, 1, 8}
正确的情况
i - low = 3 < up - i = 1
不成立(5, 5)小区间递归排序
(1, 3)大区间循环排序
{3, 2, 1}
对于
{3, 2, 1, 8}
- 3、2、8排序
{2, 3, 1, 8}
- 3放到 up - 1的位置
{2, 1, 3, 8}
- i从1加到3,3与3比较,返回true,继续比较,过程同上i = 4
- 3与8交换
{2, 1, 8, 3}
{2, 1, 8}
排序{1, 2, 8}
- 结果为
{1, 2, 8, 3}
- 3、2、8排序
最终结果为
{1, 2, 8, 3, 7}
把8换成7对数组排序{7, 2, 3, 1, 7}
,报错invalid order function for sorting
最后贴一下两个版本的源码
区别
- 结构上,5.3.5版本将获得哨兵索引的过程提取了出来
- 新版本中抛出错误的判断进行了改进
- 新版本对数量较大的排序做了优化,随机取哨兵
- 递归调用有修改,对大的一边区间做了选取哨兵的优化
1 | // 5.1.5 |
1 | // 5.3.5 |