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

Project1

 找回密码
 注册会员
搜索
查看: 7616|回复: 19
打印 上一主题 下一主题

二叉堆[更新]

 关闭 [复制链接]

Lv1.梦旅人

梦石
0
星屑
50
在线时间
238 小时
注册时间
2006-10-2
帖子
417
跳转到指定楼层
1
发表于 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用不着了。编辑之。
山寨产品龟速制作中……

Lv1.梦旅人

梦石
0
星屑
50
在线时间
7 小时
注册时间
2008-7-30
帖子
33
20
发表于 2009-4-21 02:24:12 | 只看该作者
刚才从技术区某帖找到了这一帖,猫哥哥总能写出一些很有趣的代码,呵呵~~~不过看了一下具体算法,感觉删除部分,存在问题....
运行一下这段:
ar = [1,2,3,4,5,6,7,8,9]
Binary_Head.new(ar)
ar = Binary_Head.del(ar,2)
p ar
ar = Binary_Head.del(ar,2)
p ar

出来的结果是:[1,4,3,8,5,6,7,9]
             [1,8,3,9,5,6,7]
显然第一个结果是我们想要的,但第二个,却与我们要的最小二叉堆不符了,因为最小二叉堆其父节点总小于其子节点,而明显8会大于其子节点5...所以这不是我们要的结果....
相信这只是猫哥哥一时疏忽造成的....改了一下代码,让它每次只与子节点中较小的比较,这样问题大概就能解决了...

  1. #--------------------------------------------------------------------------
  2.   # ● 删除
  3.   #--------------------------------------------------------------------------
  4.   def self.del(ar,pos) #从堆里删除数据
  5.    
  6.     if ar[pos - 1] !=nil
  7.     ar[pos - 1] = ar[ar.size - 1]; ar.pop
  8.    
  9.     loop do #比较子结点
  10.       pos_s1 = pos*2;pos_s2 = pos*2 + 1
  11.       if ar[pos_s1-1] == nil and ar[pos_s2-1] == nil #已经无子结点
  12.         break
  13.       elsif ar[pos_s2-1] == nil  #当右孩子为空时
  14.         pos_min = pos_s1     #最小节点值直接赋给左孩子
  15.       else
  16.        #比较出较小的节点
  17.        if ar[pos_s1-1] > ar[pos_s2-1]
  18.           pos_min = pos_s2
  19.         else
  20.           pos_min = pos_s1
  21.         end
  22.       end
  23.       if !fs(ar[pos-1],ar[pos_min-1])
  24.         ar[pos-1],ar[pos_min-1] = ar[pos_min-1],ar[pos-1]
  25.         pos = pos_min;next
  26.       end
  27.      
  28.         break
  29.     end
  30.    
  31.     return ar
  32.   end
  33. end
复制代码
Freedom!
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

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

第1届Title华丽大赛新人奖

19
发表于 2008-6-1 04:06:33 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

Lv1.梦旅人

雷欧纳德的宠物

梦石
0
星屑
50
在线时间
769 小时
注册时间
2006-8-6
帖子
3778

贵宾

18
发表于 2008-5-24 08:16:53 | 只看该作者
发布完毕。
http://rpg.blue/web/htm/news1067.htm
vip+4
打酱油的- -b
回复 支持 反对

使用道具 举报

Lv1.梦旅人

有事烧纸

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

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

17
发表于 2008-5-8 18:21:05 | 只看该作者
二叉树的子孙太多鸟{/qiang}
神隐中,偶尔诈尸
回复 支持 反对

使用道具 举报

Lv2.观梦者

天仙

梦石
0
星屑
610
在线时间
184 小时
注册时间
2008-4-15
帖子
5023

贵宾

16
发表于 2008-5-8 17:51:31 | 只看该作者
想起了
二元搜索樹(Binary Search Tree)才是要求不能相等的
因為搜索為目的,因此每個結點之值都是獨一無二的
{/hx}
VA脚本开工中...
偷窃脚本1.0 - 已完成
回复 支持 反对

使用道具 举报

Lv1.梦旅人

有事烧纸

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

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

15
发表于 2008-5-8 16:59:04 | 只看该作者
为啥不能有相等情况呢?
求最值并不需要保证最值得唯一性的说
神隐中,偶尔诈尸
回复 支持 反对

使用道具 举报

Lv2.观梦者

天仙

梦石
0
星屑
610
在线时间
184 小时
注册时间
2008-4-15
帖子
5023

贵宾

14
发表于 2008-5-8 14:24:16 | 只看该作者
我只是想提一下
堆的英文不是head而是heap{/pz}

MS沒人指出

另外在堆當中,MS不能有相等的值吧?
也就沒有父結點等於子結點的可能性了

還是我記錯了@@
VA脚本开工中...
偷窃脚本1.0 - 已完成
回复 支持 反对

使用道具 举报

Lv1.梦旅人

辉瑞中国首席研究员<

梦石
0
星屑
50
在线时间
142 小时
注册时间
2008-1-18
帖子
2129
13
发表于 2008-3-18 04:02:32 | 只看该作者
多么熟悉的二叉堆,久违了,让我想起了高中时的OI生涯
来6r就是等某位仁兄的巨坑

褴褛着身行无端,囊中羞涩空心酸。
平生几无得意事,倒塔泡面宅寝室。
惟羡隔壁高帅富,雨露春风月夜声。
青丝无处觅其踪,只有硬盘苍井空。
莫云男儿空悲愁,鸿鹄岂不天际游。
坐断天下执鹿首,千百金帛万兜鍪。
夜深忽梦某年月,再见女神欲语迟。
吊丝终有逆袭日,木耳再无回粉时。
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

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

第1届Title华丽大赛新人奖

12
发表于 2008-3-18 03:52:09 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-5-8 20:08

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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