1 表
typedef struct Table {
CommonHeader;
//表示这个表中提供了哪些元方法 最开始这个flags 的,也就是 ,当查找一次之后,如果该表中存在某个元方法
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of `node' array *///散列桶数组的大小的 log2(size)
struct Table *metatable;
TValue *array; /* array part */
Node *node; //散列桶数组起始位置的指针
Node *lastfree; /* any free position is before this position *///散列桶数组最后位置的指针
GCObject *gclist; //GC相关的链表
int sizearray; /* size of `array' array */
} Table;
- 桶中链地址实现的单链表靠key关联
确定数组部分大小的标准是什么呢?
- 希望在调整过后,**数组在每一个2次方位置(1开始)容纳的元素数量都超过该范围的50% ** (认为这个数组范围发挥了最大的效率)
未解疑问
- 如何触发rehash。(代码逻辑是mainPositions没有free-nil位置触发,待求证)
- hash部分的表查询如果实现??
nums数组解释:
// 只有利用率超过50%的数组元素会进入数组,否则进去hash
static int computesizes (int nums[], int *narray) {
int i;
int twotoi; /* 2^i */
int a = 0; /* number of elements smaller than 2^i */
int na = 0; /* number of elements to go to array part */
int n = 0; /* optimal size for array part */
// 这个循环完毕后,最重要的na存放的是数组部分的数据数量,而n是
// na满足这个条件:在
for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
if (nums[i] > 0) {
// 加上当前数量
a += nums[i];
// 如果数量已经超过半数, 那么数组的尺寸可以设置为这个大小
if (a > twotoi/2) { /* more than half elements present? */
n = twotoi; /* optimal size (till now) */
// 记录下当前的数组大小
na = a; /* all elements smaller than n will go to array part */
}
}
if (a == *narray) break; /* all elements already counted */
}
*narray = n;
lua_assert(*narray/2 <= na && na <= *narray);
return na;
}
举例:
1,2,5,7,8,9
数组部分的长度为4时,就不符合大于50%的使用率了。(只有1,2落入数组)
表查找
在数组部分查找数据:
- 查找成功,返回该key 的下一个数据
否则在散列桶部分查找数据:
- 查找成功,返回该key 的下一个数据
- 注意点:
1,key为1,1.0这两种情况,如何确保算出的hash值一样。答:底层都是用double来表示number。
2 扩展笔记
2.1 表"#"特性总结
- 对数组table,#取长度,底层直接获取(此时的前提是hash部分的头部node为nil),并不是遍历 (时间复杂度O(1))--luaH_getn
- 对混合型table,#取长度,结果不可靠。 并不是返回前面数组的长度(这是误解,而是根据元素情况不定,可能会使用二分查找遍历或者其他--具体不纠缠)
Lua源码阅读笔记 - table的长度