stl 基于哈希的map c++_【UE4 Renderer】<06> TMap基于 哈希表 or 红黑树

f4bb8f6e5c0a33e3f6d91a29a5a2e2a2.png

STL的关联式容器map选择基于<Red-Black Tree红黑树>

UE4的关联式容器TMap选择基于<HashTable哈希表>

数组的特点:查询效率高,添加、删除效率低

链表的特点:查询效率低,添加、删除效率高

-->二叉树本质上是一种基于链表的数据结构,查询复杂度为

-->哈希表本质上是一种基于数组的数据结构,查询复杂度为

<1> STL和UE4采用不同实现策略的主要原因

--STL的map面向通用需求:查找和排序,增删有序

--UE4的TMap面向渲染系统:主要是查找,偶尔需要有序

<2> TMap在渲染管道中的应用

d6a3bbc056fddfd00e1adc43a441c3d1.png

--可以看到大部分的应用情况:

---在Mesh/Material/Shader的组织和处理过程不需要TMap时刻有序

<3> Red-BlackTree红黑树

红黑树是平衡二叉树的一种,需要先来理解一下平衡二叉树的概念

dc7b0bb1a0c9716606c7d1c23c0b0427.png
不平衡

a0802bc01b792d081e0924601e3c34c2.png
平衡

完全平衡二叉树的特点

--1> 任一节点的左右两个子树的高度差的绝对值不超过1

--2> 任一节点的左右两个子树都是一棵平衡二叉树

--3> 节点的设计

73c96a14caf9492ca0f298bb01975431.png

AVL树

--> Adelson-Velskii & Landis在1962年的论文中发表,是一种完全平衡的二叉树

--> 实现平衡的方式

------> 左/右旋转

7b5132442597a1f96731caacc782047a.png

8d8203c4ad45f2f7c98d9f76356caa52.png

08068e1bca82e04abe11e838980f1f1e.png

00822140d45fa8f67830a2340f3b7c94.png

------> 基于左/右旋转的双旋转

689fb24d5c5a3470f532e5f385b07e2c.png

7c01879d44e0a28fe384af306237185f.png

41301cc8168a8c012bc56cb266b82ca1.png

72c529ed022767c9eb7fdc3ec24a0513.png

7a0a3be25cc375b81589c71c13b429d6.png

------> 自顶向下的平衡

570aac7d77e312d9d0381db0c35c624b.png

8e41a70802201b6a444310abda6953e3.png

从根节点开始逐级进行平衡

dc8addb70c11a175414091f43e30fcef.png

05bb585fce1d2cdfa8a9aed50bee4578.png

f6b0d16713d5d4832d57e30b88d95aa0.png

b7747edc91b88a28d0a52084e1545618.png

红黑树

AVL树为了完全平衡需要做大量旋转,为了更好的性能,红黑树并不要求严格的平衡,通过标记树节点的颜色和限制特定颜色节点的数量进行平衡控制,左右旋转、双旋转在AVL树旋转的基础上增加了颜色控制

--1> 根节点必须为黑色

2a7bbd55460fa48f0d83141cd4d73bf3.png

--2> 任一节点的任一路径黑节点数量相同

--3> 红节点的子节点必须为黑

3a4ac0dd271db57ee1768f5dad841852.png

--4> 平衡规则:自下而上

----不同于AVL树插入节点后从根节点开始自上而下逐级平衡,红黑树则是从插入节点位置逐级向上平衡

26ad45df7f89fbe0514c3569c8eccd2e.png

----GP为根节点

739110d4d7bafd2fa26f860336968c8b.png

6d8522287513079344095260058f6b95.png

59e4f6918bd22b7d5917342a800ebf07.png

c8ad4d74678e84ea617715a299ffd7c6.png

----GP不为根节点

88a64891baef014c93f4dc42078a5ac7.png

40db533d351a7c871281854f493f1124.png

e01ff9c5f55b924c6f78703cba1b87ca.png

574a7af607aee3eced6bbe7c6703360f.png

0ef6710eaaeb72b42e9e5d95b9a40c6f.png

可视化

01818472f9762218b13322af6fc49229.png

-通过GeometryShader实现,分2个Pass

--<1> 显示线

3afc1e34d16cbb5a5b298fd886c47ad8.png

bc0824d2acd63c25855b9f2f05607c1e.png

344f43a1d9c4620f164b62e8feb6de21.png

8f6d172ec20408d762799cef8c23a01c.png

359a00fd22025368de4f17662f9fd2d1.png

189a9aa31e502d14bc7a18339a765604.png

--<2> 显示节点

103a4738d2a67d72bcf50cf0cfe433b2.png

-----TextureArray通过TexAssemble 工具生成

texassemble array -o RedArray.dds Red0.png Red1.png Red2.png Red3.png Red4.png Red5.png Red6.png 
Red7.png Red8.png Red9.png Red10.png Red11.png Red12.png Red13.png Red14.png Red15.png

94021c866a23901e288845436dd388b3.png

----TextureArray的使用

35ec2112824c27f96efdc4e2be2a4742.png

<4> HashTable哈希表

7746f3ed600b2e08279e2b391a238310.png

UE4基于两个Array实现TMap

---> 一个HashArray

----- 数组下标即HashIndex哈希值,存储在ElementArray中对应的ElementId

----- 哈希值的计算通过可以自定义的哈希函数,将结果对HashSize取余

---> 一个ElementArray

----- 考虑增删问题而采用SparseArray,存储Element以及相同哈希值的链表

11ec7d1d327e13d231df6b24a2e4dace.png
TMap添加第一个Element - Key 2 Value 1000

--->如果HashIndex相同,通过HashBucket链表的方式依次指向后续Element

3cf7be64f40906c4dfebea1ed637446d.png

----UE4并没有在HashBucket链表长度大于8时转换为红黑树存储

a3bbfd3a060dfb292673f1b0df5e4f8c.png

TMap的排序Sort

-----排序Sort

8b45923c0b42e42c53071adf7150713f.png

-----排序Sort

-------<1> 排序 ElementArray

0d251083b78f16b9f9c02a6c5ee5e137.png

-------<2> 更新 HashArray

132f92f9740c1745dd2c6e5387cd2b43.png

--为什么UE4选择快速排序QuickSort

---主要的Array排序方案:

-----InsertSort插入排序 - 时间复杂度

-----BubbleSort冒泡排序 - 时间复杂度

-----QuickSort快速排序 - 时间复杂度

实测数量为64000个随机数的Array各种排序方案的性能表现

5b5385a8b8c1fe64fe22028d2f71c08f.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值