找回密码
 点一下
查看: 5306|回复: 27

<< HASH+Struct 雙鍊,完全取代 GC 之最強的數據系統!>>

[复制链接]
发表于 2009-5-2 14:38:50 | 显示全部楼层 |阅读模式
類似這樣的東西早就有人做過了,說明也解釋過了,但我仍不厭其煩的再介紹一次
HASH+Struct 雙鍊、多鍊系統,有一條主鍊與8191條小鍊

主鍊負責資源的分配,就跟普通的Struct沒有差別
小鍊負責搜尋與綁定,當I-I*8191/8191的HASH值產生衝突的時候
會有一個以上的資料落在同一條小鍊上,這時候循著小鍊做「線的遍歷」就可以快速的找到資料
不用像其他HASH採用亂槍打鳥的方式去搜尋

這次發表的函數分成三個部分

初始化、普通Struct、雙鍊Struct

可以直接綁定Timer、Trigger,模擬一般HASH的功能
而這系統也支持使用String綁定數據,因此完完全全的取代掉GC的地位

唯一的缺點是8191上限問題,但要模擬8191以上的陣列並不困難
假如有需要也可以簡單的突破這個限制,所以整體來說沒有任何限制


[jass]//===========================================================================
//                  Return Bug
//===========================================================================
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function H2S takes handle h returns string
    return I2S(H2I(h))
endfunction

function RBS2I takes string s returns integer
    return s
    return 0
endfunction



//===========================================================================
//                  K DataSystem Int
//===========================================================================

function K_DataSystem_Int1 takes nothing returns nothing
local integer A = 4000
    loop
        exitwhen A > 8191
        set udg__TimK[A] = CreateTimer()
        set A = A+1
    endloop
endfunction

function K_DataSystem_Int takes nothing returns nothing
local integer A = 1
local trigger T = CreateTrigger()
local triggeraction TA = TriggerAddAction(T, function K_DataSystem_Int1)
    set udg__TimK[0] = CreateTimer()
    set udg_K_Hash_Start = H2I(udg__TimK[0])
    set udg_K_Struct_Now = 0
    set udg_K_Struct_Max = 0
    set udg__Int1[0] = 0
    set udg__Int0[99] = 0
    loop
        exitwhen A >= 4000
        set udg__TimK[A] = CreateTimer()
        set A = A+1
    endloop
    call TriggerExecute(T)
    call TriggerRemoveAction(T,TA)
    call DestroyTrigger(T)
    set T = null
    set TA = null
endfunction
[/jass]


這沒甚麼好講的,就是把該歸零的數據歸零,確保不會發生問題
然後連續創造8191個Timer用來做最高效率的TimerHASH

TimerHASH是效率最高的HASH,只綁定Timer的時候,我們沒有理由不用它


[jass]//===========================================================================
//                  TimerHASH+Struct 適用於需要 Timer 的函數
//===========================================================================
// 用最高效率的 TimerHASH 來跑所有需要 Timer 的函數

function GetK takes nothing returns integer
local integer K = udg_K_Struct_Now //線頭
    if K != 0 then  //有經過回收則
        set udg_K_Struct_Now = udg_K_Struct_ReUse[K] //取第二個為線頭
    else  //否則
        set udg_K_Struct_Max = udg_K_Struct_Max + 1
        set K = udg_K_Struct_Max //取最大值使用
    endif
    //不考慮超過8191的情況,因此省略原本Struct之除錯
    return K
endfunction

function LoadK takes nothing returns integer
    return H2I(GetExpiredTimer()) - udg_K_Hash_Start
endfunction

function EndK takes integer K returns nothing
    //不考慮誤用的情況,因此省略原本Struct之除錯
    call PauseTimer(udg__TimK[K])
    set udg_K_Struct_ReUse[K] = udg_K_Struct_Now    //原線頭降為第二個
    set udg_K_Struct_Now = K  //保存新線頭
endfunction
[/jass]

傳說中的TimerHASH
利用Timer的H2I減去初始化計算出的Timer[0]的H2I,獲得陣列的編號,是目前效率最高的HASH
但缺點是只針對Timer綁定,而且只能用初始化創造的Timer跑TimerStart才有效(也就是針對udg__TimK[K])


[jass]//===========================================================================
//                  HASH+Struct
//===========================================================================
// 用多鏈狀結構 Struct,用線的遍歷搜索資料,通常線的長度只有1

function GetKM takes integer I returns integer
local integer Hash=I-I/8191*8191
local integer K = GetK() //直接抓Struct的值
    if udg_K_Struct_Mult_Now[Hash] != 0 then //小鍊的線頭不為零,表示之前已經被用過了
        set udg_K_Struct_Mult_ReNow[udg_K_Struct_Mult_Now[Hash]] = K   //形成每個Hash值的小鍊,由後向前接
    endif
    set udg_K_Struct_Mult_ReUse[K] = udg_K_Struct_Mult_Now[Hash]   //形成每個Hash值的小鍊,由前向後接
    set udg_K_Struct_Mult_Now[Hash] = K   //形成每個Hash值的小鍊
    set udg_K_Struct_Mult_H2I[K] = I
    set udg_K_Struct_Mult_Hash[K] = Hash
    return K
endfunction

function LoadKM takes integer I returns integer
local integer Hash=I-I/8191*8191
local integer K = udg_K_Struct_Mult_Now[Hash] //抓到Hash值的小鍊線頭
    loop
        exitwhen udg_K_Struct_Mult_H2I[K] == I or K == 0 // 防錯 V006
        set K = udg_K_Struct_Mult_ReUse[K]
    endloop //鍊的遍歷,逐一搜尋小鍊的值去比對
    return K   //若未註冊則 return 0
endfunction

function EndKM takes integer K returns nothing
local integer Hash=udg_K_Struct_Mult_Hash[K]
local integer TempK=udg_K_Struct_Mult_Now[Hash] //抓到Hash值的小鍊線頭
    if TempK != K then    //如果小鍊的結構在一段以上,就重新執行雙向連接,將這段從鏈中消去
        set udg_K_Struct_Mult_ReUse[udg_K_Struct_Mult_ReNow[K]] = udg_K_Struct_Mult_ReUse[K]
        set udg_K_Struct_Mult_ReNow[udg_K_Struct_Mult_ReUse[K]] = udg_K_Struct_Mult_ReNow[K]
    else
        set udg_K_Struct_Mult_Now[Hash] = udg_K_Struct_Mult_ReUse[K] //如果小鍊是線頭,就把線頭連接到下一節
    endif
    call EndK(K)
endfunction
[/jass]

雙鍊Strict,也就是泛用型的HASH
原理開頭講過了,詳細思路不容易解釋,請自行研究

功能為傳入任意integer給GetKM即可綁定資料並獲得一個K用於DataSystem之應用
下次只要傳入相同的integer給LoadKM即可拿回這個K

EndKM則是回收用


[jass]//===========================================================================
//                  Handle 一對一綁定資料,適用於 Trigger
//===========================================================================
// H2I 值在一百萬以上,S2I 值從0開始,因此排除衝突的可能
// 在衝突前魔獸已經LAG到掛掉了

function GetKH takes handle H returns integer
    return GetKM(H2I(H))
endfunction

function LoadKH takes handle H returns integer
    return LoadKM(H2I(H))
endfunction


//===========================================================================
//                  String 用來綁定一個 Hanedle 多個資料,適用於 Unit
//===========================================================================
// H2I 值在一百萬以上,S2I 值從0開始,因此排除衝突的可能
// 在衝突前魔獸已經LAG到掛掉了

function GetKS takes string S returns integer
    return GetKM(RBS2I(S))
endfunction

function LoadKS takes string S returns integer
    return LoadKM(RBS2I(S))
endfunction


[/jass]

很簡單,就是分別針對Handle跟String製作對GetKM的接口

資源回收就直接用EndKM了,要我做貌似BJ的雞肋函數我做不到...




底下附上演示地圖,漂亮的煙花V006版,作者就是我,千萬別懷疑... XD
[WB]2009 0214 JASS Sparkler.JPG

[WB]2009 0501 JASS Sparkler K V006.w3x

28 KB, 下载次数: 73

评分

参与人数 1威望 +5 收起 理由
kook + 5 优秀演示

查看全部评分

发表于 2009-5-2 15:39:19 | 显示全部楼层
lz怎么有心情来ga注册啦~- -
回复

使用道具 举报

 楼主| 发表于 2009-5-2 17:47:10 | 显示全部楼层
我從 2008 年中就一直嘗試著註冊 GA,但Email認證無法成功

最近才成功註冊進來的
回复

使用道具 举报

发表于 2009-5-2 18:28:07 | 显示全部楼层
ga啥时候需要email验证了...
回复

使用道具 举报

 楼主| 发表于 2009-5-2 18:48:25 | 显示全部楼层
E-Mail 驗證

2008 年中到今年 4 月左右都需要驗證
幾天之前才解除,我跟我朋友也是趁這幾天才註冊成功的
回复

使用道具 举报

发表于 2009-5-2 19:37:49 | 显示全部楼层
实际上GA根本没邮件服务器~~所以是没法进行email验证的~~
回复

使用道具 举报

发表于 2009-5-2 19:40:41 | 显示全部楼层
如果真有这个问题我怀疑是内部人员乱改所致~~
回复

使用道具 举报

发表于 2009-5-2 19:57:55 | 显示全部楼层
那么很需要查一查了,如果真有问题对GA的人气很有影响的
回复

使用道具 举报

 楼主| 发表于 2009-5-3 01:45:36 | 显示全部楼层
我很早之前就想入境GA了
礙於註冊問題,才只在U9跟心魔那邊發表文章


不過,我想也該討論主題了,對於這系統大家有甚麼看法嗎?
回复

使用道具 举报

发表于 2009-5-3 11:44:19 | 显示全部楼层
有什么用?应用。
回复

使用道具 举报

发表于 2009-5-3 17:22:36 | 显示全部楼层
很漂亮.
记得很早就在其他地方发过这个把
回复

使用道具 举报

 楼主| 发表于 2009-5-3 22:06:07 | 显示全部楼层
數據系統部分是 2009 05 01 才寫出的版本
效能更好,也加入更多防錯機制
至於煙火的函數確實是舊的,因為那不是重點


這系統可以有效率的實現多重施展
用來寫模擬腐蝕波、模擬跳斬,會非常方便

大致上用法跟 ReturnBug + GC 差不多
而且效能更好

還沒基礎的可以參考 RedWolf 的 ReturnBug + GC 教程

GUI 使用者就 54 這東西吧
回复

使用道具 举报

发表于 2009-5-3 22:09:38 | 显示全部楼层
game cache~~这个是我一直提倡弃用的系统~~Game Cache应该只适用于单人地图之间传递数据~~而不该放在地图内部进行数据保存~~

毕竟一来它慢~~这是最严重的问题~~二来其不稳定性也是个大问题~~比如用了Game cahe的地图很容易就会导致地图回放失常~~这种还是比较常见的症状~~

因此自行开发系统来将之替代是值得提倡的~~
回复

使用道具 举报

发表于 2009-5-4 00:09:03 | 显示全部楼层
WB兄好,没想到在Ga也看到你发贴了,呵呵。

嗯,你的拉链Hash中,函数GetKM和LoadKM有一些问题。
在传入一个句柄需要其返回一个整数时,GetKM一定要在运行LoadKM之后才可以调用。因为如果对函数GetKM传入同一个整数两次的话,它一定会给这个整数分配两个地址,所以至少函数GetKH应该修改为:
[codes=jass]
function GetKH takes handle H returns integer
    local integer i=H2I(H)
    local integer x=LoadKM(i)
    if x==0 then
        return GetKM(i)
    endif
    return x
endfunction[/codes]

也许你认为这两个函数的调用场合不同,所以不需要多此一举,但是你要知道,在代码中可能出现错误的地方就一定会出现错误,而且这个东西发表出来是要对读者负责的,这个细节虽然不算是Bug,但是还是修改过来为好。

同样的问题也出现在函数GetK中,在我认为,判断K获取的值是否大于8191是完全必要的,理由同上。

嗯,还希望我没有说错什么。
回复

使用道具 举报

 楼主| 发表于 2009-5-4 00:26:18 | 显示全部楼层
確實是個 BUG,感謝提醒

雖然這個 BUG 的起因是「誤用」,但我們也不能確保使用者都會正確的使用他們
所以這個防錯是必須的

另外最近也打算把 ReturnBug 用 Union Bug 取代
因為 Union Bug 效能會更好一點

下個版本再說囉... @@"
回复

使用道具 举报

 楼主| 发表于 2009-5-4 00:32:49 | 显示全部楼层
過 8191 的防錯沒有必要
若沒VJ輔助,過了8191之後這函數就壞掉了,沒有任何方法可以防錯
若有VJ輔助,讓陣列上限超過8191,那當然也沒這問題

所以我才拿掉這雞肋的東西
回复

使用道具 举报

发表于 2009-5-4 00:57:52 | 显示全部楼层
引用第15楼weberkx3于2009-05-04 00:32发表的  :
過 8191 的防錯沒有必要
若沒VJ輔助,過了8191之後這函數就壞掉了,沒有任何方法可以防錯
若有VJ輔助,讓陣列上限超過8191,那當然也沒這問題

所以我才拿掉這雞肋的東西

并非是這樣,在沒有防錯機制下,你的函數GetKM可能會使用一個大於8191的整數用于存儲數據,這樣這個函數真的是壞掉了。
但是如果有防錯的設置,比如在udg_K_Struct_Max超過了8191之後,函數GetKM返回一個0,這個至少在Debug中是很有用的,可以讓編圖者知道自己犯了錯誤,或者編圖者也可以針對返回的整數為0這個情況采取一些別的措施,至少可以避免地圖在之後出現更離譜的錯誤。
回复

使用道具 举报

 楼主| 发表于 2009-5-4 01:24:18 | 显示全部楼层
了解...
主要是擔心讀取超過 8191 的陣列,產生非預期的錯誤

不過一般地圖用超過 2000 就很多了,所以總是覺得 8191 是個很遙遠的數字
回复

使用道具 举报

发表于 2009-5-4 01:33:18 | 显示全部楼层
呵呵,同感。

其實我提出的這些意見只是細枝末節而已,但是我覺得,如果想要推廣這個數據系統的話,最重要的就是模板化,而一個模板化的東西,最好是沒有能挑得出錯誤的地方。
回复

使用道具 举报

发表于 2009-5-4 12:49:32 | 显示全部楼层
这些都是数据结构基本常识呢。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-4-20 06:28 , Processed in 0.220951 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表