標籤:style blog color 使用 資料 io
table是Lua中唯一的資料結構,其他語言所提供的資料結構,如:arrays、records、lists、queues、sets等,Lua都是通過table來實現,並且在Lua中table很好的實現了這些資料結構。
1、數組
在Lua中通過整數下標訪問table中元素,既是數組,並且數組大小不固定,可動態增長。通常我們初始化數組時,就間接地定義了數組的大小,例如:
1 a = {} -- new array 2 for i=1, 1000 do 3 a[i] = 0 4 end 5 6 --數組a的大小為1000,訪問1-1000範圍外的值,將返回nil。 7 --數組下標可以根據需要,從任意值開始 8 -- creates an array with indices from -5 to 5 9 a = {}10 for i=-5, 5 do11 a[i] = 012 end
然而習慣上,Lua的下標從1開始。Lua的標準庫遵循此慣例,因此你的數組下標必須也是從1開始,才可以使用標準庫的函數。
我們可以用構造器在建立數組的同時初始化數組,這樣數組的大小可以任意的大。
1 squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}
2、矩陣和多維陣列
Lua中有兩種表示矩陣的方法,一是"數組的數組",也就是table的每個元素是另一個table。
--可以使用下面代碼建立一個n行m列的矩陣mt = {} -- create the matrixfor i=1,N do mt[i] = {} -- create a new row for j=1,M do mt[i][j] = 0 endend--由於Lua中table是對象,所以每一行我們必須顯示地建立一個table,比起c這顯得冗餘,--但另一方面也提供了更多的靈活性,比如可修改前面的例子建立一個三角矩陣for j=1,M do --修改為 for j=1,i do--這樣實現的三角矩陣比起整個矩陣,僅適用一半的記憶體空間
表示矩陣的另一方法,是將行和列組合起來。如果索引下標都是整數,通過第一個索引乘於一個常量(列)再加上第二個索引。
1 --看下面的例子實現建立n行m列的矩陣2 mt = {} -- create the matrix3 for i=1,N do4 for j=1,M do5 mt[i*M + j] = 06 end7 end
如果索引是字串,可用一個單字元將兩個字串索引串連起來構成一個單一的索引下標。
3、鏈表
Lua中用tables很容易實現鏈表,每一個節點是一個table,指標是這個表的一個域(field),並且指向另一個節點(table)。
1 --要實現一個只有兩個域:值和指標的基本鏈表 2 3 --根節點 4 list = nil 5 6 --在鏈表開頭插入一個值為v的節點 7 list = {next = list, value = v} 8 9 --要遍曆這個鏈表只需要10 local l = list11 while l do12 print(l.value)13 l = l.next14 end
其他類型的鏈表,像雙向鏈表和迴圈鏈表類似的也是很容易實現的。在Lua中,很少情況下才需要這些資料結構,因為通常情況下有更簡單的方式來替換鏈表。比如:我們可以用一個非常大的數組來表示棧,其中一個域n指向棧頂。
4、隊列和雙向隊列
雖然可以使用Lua的table庫提供的insert和remove操作來實現隊列,但這種方式實現的隊列針對大資料量時效率太低,有效方式是使用兩個索引下標,一個表示第一個元素,另一個表示最後一個元素。
1 function ListNew () 2 return {first = 0, last = -1} 3 end 4 5 --為了避免汙染全域命名空間,我們重寫上面的代碼,將其放在一個名為list的table中 6 List = {} 7 function List.new () 8 return {first = 0, last = -1} 9 end10 11 --下面,我們可以在常量時間內,完成在隊列的兩端進行插入和刪除操作了12 function List.pushleft (list, value)13 local first = list.first - 114 list.first = first15 list[first] = value16 end17 18 function List.pushright (list, value)19 local last = list.last + 120 list.last = last21 list[last] = value22 end23 24 function List.popleft (list)25 local first = list.first26 if first > list.last then error("list is empty") end27 local value = list[first]28 list[first] = nil -- to allow garbage collection29 list.first = first + 130 return value31 end32 33 function List.popright (list)34 local last = list.last35 if list.first > last then error("list is empty") end36 local value = list[last]37 list[last] = nil -- to allow garbage collection38 list.last = last - 139 return value40 end
對嚴格意義上的隊列來講,我們只能調用pushright和popleft,這樣以來,first和last的索引值都隨之增加,幸運的是我們使用的Lua的table實現的,你可以訪問數組的元素,通過使用下標從1到20,也可以16,777,216帶16,777,236。另外Lua使用雙精確度表示數字,假定你每秒鐘執行100萬次插入操作,在數值溢出以前你的程式可以運行200年。
5、集合和包
假定你想列出在一段原始碼中出現的所有標示符,某種程度上,你需要過濾掉那些語言本身的保留字。一些C程式員喜歡用一個字串數組來表示,將所有的保留字放在數組中,對每一個標示符到這個數組中尋找看是否為保留字,有時候為了提高查詢效率,對數組儲存的時候使用二分尋找或者hash演算法。
Lua中表示這個集合有一個簡單有效方法,將所有集合中的元素作為下標存放在一個table裡,不需要尋找table,只需要測試看對於給定的元素,表的對應下標的元素值是否為nil。
1 reserved = { 2 ["while"] = true, ["end"] = true, 3 ["function"] = true, ["local"] = true, 4 } 5 6 for w in allwords() do 7 if reserved[w] then 8 -- `w‘ is a reserved word 9 ...10 11 --還可以使用輔助函數更加清晰的構造集合12 function Set (list)13 local set = {}14 for _, l in ipairs(list) do set[l] = true end15 return set16 end17 18 reserved = Set{"while", "end", "function", "local", }