一种高效的可变行高列表行定位算法

列表控件是数据显示时使用的一种常用的控件。

刚发现有网友把这个算法说得更清楚,推荐大家去它的博客看https://www.jianshu.com/p/76827322f33f

下面是我提供的原始的版本 :)

一般情况下列表中的行是等高的,这种情况下无论列表包含多少行,都能够在O(1)的时间定位到指定行。

但是当显示的内容格式不一致时,使用相等的行高可能就意味着显示空间的浪费,也意味说用户需要更多的滚动操作,影响用户体验。

要实现一个支持可变行高的列表控件,首先要解决的问题就是快速定位列表行。

假定一个列表中的表项按照下面的高度排列:

1,2,3,1,2,3,1,2,3,1,2,3,4,5

可以知道总高度为:33

程序员需要解决从一个随机的[0,32]的值(x)定位到哪一行的问题。

当然最简单的办法就是从第一行开始逐行的数,直到数到的那一行正好包含x,可以知道这个算法的时间复杂度为O(n)。

当n很大时,这个算法基本上不可行。

一行一行的数显然是很浪费时间的,解决的办法就是一段一段的数。

要实现分段数,一个前提就是我们需要为这些数据提前建立好索引表。对于上面序列假定以3个元素一组为单位建立索引表就可以获得:(6),(6),(6),(6),(9),如此一来,要定位一行,我们最多需要数5+3次就能找到一行。

对于数据量比较少的情况,可能上述分组方法就能解决问题了。

但是对于数据量更大的情况如何处理呢?方法很简单,那就是分组再分组,直到最后所有的分组数据形成一棵索引树。树上每一个结点代表该结点下所有子节点的高度和。

通过构造索引树,无论多少数据量,都可以在O(log(n))的时间定位到任意行。

另外,对于大量数据,我们可能在初始化的时候并不知道总数有多少,而是在显示到哪一行时再通过计算获得。

对于这种情况,我们需要动态更新索引树。更新过程也很简单,当一行更新高度时,只需要找到该行所在的叶节点,更新叶节点高度,再逐级更新父节点即可,时间复杂度同样是O(log(n))。

具体实现可以参考SOUI的ListView中用于可变行高支持的类:SListViewItemLocatorFlex

原文地址:https://www.cnblogs.com/setoutsoft/p/4711139.html