设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 7600|回复: 19

二叉堆[更新]

 关闭 [复制链接]

Lv1.梦旅人

梦石
0
星屑
50
在线时间
238 小时
注册时间
2006-10-2
帖子
417
发表于 2008-3-17 19:02:07 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
    在论坛里搜索“二叉堆”,没有结果。于是把自己写的发出来。或许还有不正确、不成熟的地方,请指正。
    至于,二叉堆可以做什么……将一个数插入到10000个数的数组中,在顺序排列结构的数组里,挨个比较的方法来确定新插入数的位置,最坏的情况得比较10000次;如果用二叉堆的结构,节点比较,最坏的情况则需要比较13次。
    有时候,我们需要的仅仅是最大值(最小值),比如在A*寻路里面,取最小F值,就可以应用到二叉堆。



二叉堆(Binary Head)是什么?
    二叉堆是一种特殊的堆,二叉堆是完全二元树或者是近似完全二元树。二叉堆满足堆特性:父结点的键值总是大於或等于任何一个子节点的键值。如果想了解更多的内容,在搜索引擎里搜一下吧,也不是一两句话能说清楚,篇幅有限就不赘述了。脚本的具体用法,在脚本里有标注。

  1. #==============================================================================
  2. # ■ Binary_Head
  3. #                     by 猫哥哥
  4. #------------------------------------------------------------------------------
  5. #  将数组(Array)转化为二叉堆,并实现堆数据的添加、删除和修改的模块。此模块的使
  6. # 用方法见脚本内容。此为最小堆。如果要用最大堆,把脚本里的"<="和">="替换一下就
  7. # 行了。
  8. #==============================================================================
  9. # 使用方法:
  10. #
  11. #  Binary_Head.new(ar)            将数组ar转化为二叉堆
  12. #
  13. #  Binary_Head.add(bh,item)       往二叉堆bh里,添加数据item
  14. #
  15. #  Binary_Head.del(bh,pos)        删除二叉堆bh里,第pos个数据
  16. #
  17. #  Binary_Head.alt(bh,pos,item)   修改二叉堆bh里的第pos个数据的值
  18. #==============================================================================
  19. #  示例:
  20. #   eg = [10,30,24,34,38,30,20]
  21. #   eg = Binary_Head.new(eg)      
  22. #   p eg                          # => [10,30,20,34,38,30,24]
  23. #   eg = Binary_Head.add(eg,17)
  24. #   p eg                          # => [10,17,20,30,38,30,24,34]
  25. #   Binary_Head.del(eg,1)
  26. #   p eg                          # => [17,30,20,34,38,30,24]
  27. #
  28. #==============================================================================
  29. module Binary_Head
  30.   #--------------------------------------------------------------------------
  31.   # ● 转化
  32.   #--------------------------------------------------------------------------  
  33.   def self.new(ar) #数组转化为二叉堆
  34.    
  35.     ar_n = []
  36.     if ar.class != Array
  37.         p "数据类型不正确";exit
  38.     end

  39.     for i in ar
  40.       add(ar_n,i)
  41.     end
  42.    
  43.     return ar_n #生成堆
  44.   end
  45.   #--------------------------------------------------------------------------
  46.   # ● 添加
  47.   #--------------------------------------------------------------------------
  48.   def self.add(ar,item) #往堆里添加数据

  49.     ar.push item
  50.     pos = ar.size
  51.     loop do #比较父节点
  52.       if pos == 1 #已经在顶端
  53.         break
  54.       end
  55.       pos_f = pos/2
  56.       if ar[pos-1] >= ar[pos_f-1]
  57.         break
  58.       else
  59.         ar[pos_f-1],ar[pos-1]=ar[pos-1],ar[pos_f-1] #交换子结点与父节点
  60.         pos = pos_f #传递下标
  61.       end
  62.     end
  63.    
  64.     return ar
  65.   end
  66.   #--------------------------------------------------------------------------
  67.   # ● 删除
  68.   #--------------------------------------------------------------------------
  69.   def self.del(ar,pos) #从堆里删除数据
  70.    
  71.     if ar[pos - 1] !=nil
  72.     ar[pos - 1] = ar[ar.size - 1]; ar.pop
  73.    
  74.     loop do #比较子结点
  75.       pos_s1 = pos*2;pos_s2 = pos*2 + 1
  76.       if ar[pos_s1-1] == nil and ar[pos_s2-1] == nil #已经无子结点
  77.         break
  78.       end
  79.       if !fs(ar[pos-1],ar[pos_s1-1])
  80.         ar[pos-1],ar[pos_s1-1] = ar[pos_s1-1],ar[pos-1]
  81.         pos = pos_s1;next
  82.       end
  83.       if !fs(ar[pos-1],ar[pos_s2-1])
  84.         ar[pos-1],ar[pos_s2-1] = ar[pos_s2-1],ar[pos-1]
  85.         pos = pos_s2;next
  86.       end
  87.         break
  88.     end
  89.    
  90.     return ar
  91.   end
  92.   end
  93.   
  94.   def self.fs(father,son)
  95.     if son == nil
  96.       true
  97.     else
  98.       father <= son ? true : false
  99.     end
  100.   end
  101.   #--------------------------------------------------------------------------
  102.   # ● 修改
  103.   #--------------------------------------------------------------------------
  104.   def self.alt(ar,pos,item) #修改数据
  105.    
  106.     del(ar,pos);add(ar,item)
  107.     return ar   
  108.   end
  109.   
  110. end
复制代码



以下为更新
早上进6r我这里网速还比较快,其他时间根本进不来,后来发现还有无图版能凑合凑合……趁现在能上有图版时编辑一下帖子= =

    我一直在思考一个问题。在生成最小堆的时候,或许可以用Array.sort来生成,会比较快,当然要是最大堆的话,再Array.reverse反转一下。由于最后生成的数组是升序排序(降序排序)的,其后面的数总大于等于(小于等于)前面的数。比如,array[p]<=array[p*2] array[p]<=array[p*2+1],满足二叉堆的性质。

  1.   #--------------------------------------------------------------------------
  2.   # ● 转化
  3.   #--------------------------------------------------------------------------  
  4.   def self.new(ar) #数组转化为二叉堆结构
  5.    
  6.     if ar.class != Array
  7.         p "数据类型不正确";exit
  8.     end

  9.     ar=ar.sort #生成最小堆
  10.    
  11.     return ar
  12.   end
复制代码



    看了大家的讨论,自己动手测试了一下。
    仅就单次求最值的话,用ruby自带的sort排序会快很多,min和max也是。
    二叉堆的快速,只是体现在了之后维护新的数据节省的时间上吧。


突然想起Ruby里可以直接用a,b=b,a来交换变量……脚本里传递变量的temp用不着了。编辑之。
山寨产品龟速制作中……

Lv2.观梦者

酱油的

梦石
0
星屑
945
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

发表于 2008-3-17 19:07:49 | 显示全部楼层
很强大的腳本,雖然暫時腦殘想不到用來寫甚麽==a
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
238 小时
注册时间
2006-10-2
帖子
417
 楼主| 发表于 2008-3-17 19:22:08 | 显示全部楼层
除了A*寻路能用到以外,我也没想到还能干嘛= =
……或许还能在战棋或者ARPG做怪物的AI时,用来判断一下行动价值之类的
山寨产品龟速制作中……
回复 支持 反对

使用道具 举报

Lv5.捕梦者

御灵的宠物

梦石
12
星屑
8438
在线时间
88 小时
注册时间
2006-12-11
帖子
3148

第2届TG大赛亚军

发表于 2008-3-17 19:24:43 | 显示全部楼层
OJZ,没认真看,脑残了……
我的Lofter:http://nightoye.lofter.com/

回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
46
在线时间
10 小时
注册时间
2007-5-27
帖子
2558

第1届Title华丽大赛新人奖

发表于 2008-3-17 19:37:24 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
0 小时
注册时间
2008-2-23
帖子
115
发表于 2008-3-17 19:43:03 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
46
在线时间
10 小时
注册时间
2007-5-27
帖子
2558

第1届Title华丽大赛新人奖

发表于 2008-3-17 19:51:13 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

有事烧纸

梦石
0
星屑
154
在线时间
509 小时
注册时间
2005-10-22
帖子
6982

贵宾VX城市地图大赛冠军第1届RMTV比赛冠军第1届TG大赛冠军

发表于 2008-3-17 20:11:31 | 显示全部楼层
除了写A*的时候用过还米在别的地方用到过二叉堆-口-
不过用二叉堆的确是非常适合用来维护A*的开启列表{/qiang}

以下引用沉影不器于2008-3-17 11:37:24的发言:

瞅瞅...好像就是二叉树


二叉堆就是存放堆的二叉树{/hx}
神隐中,偶尔诈尸
回复 支持 反对

使用道具 举报

Lv1.梦旅人

月下可怜人

梦石
0
星屑
50
在线时间
10 小时
注册时间
2005-11-23
帖子
4085

第1届短篇游戏比赛亚军

发表于 2008-3-17 22:58:34 | 显示全部楼层
一般对于想快速需求最值的环境下,都能用的上,例如棋类搜索,评估等。

在处理大数据量时效果比较明显,数据量很小时反而显的累赘,与普通的二叉树相比强调节点顺序。
纵然千里外,我等雁归来。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

风雪夜不归人

梦石
0
星屑
50
在线时间
276 小时
注册时间
2006-3-7
帖子
6721

贵宾

发表于 2008-3-18 00:09:36 | 显示全部楼层
= =我不行了...........
有些人,到了七八月份就会诈尸。
宫斗,是女生永远的爱。
冷门,是本人不变的欲。
作弊,是玩家自由的痛。
练级,是橙光割舍的情。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-19 09:09

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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