+ -
当前位置:首页 → 问答吧 → 翻页区间切割算法(PHP实现)

翻页区间切割算法(PHP实现)

时间:2009-02-19

来源:互联网

在Web应用程序中,我们经常会见到同一类数据经过视图层的渲染,以“分页显示”和“翻页链接”的形式展现在客户端。下图是Google搜索结果页中的“翻页链接”。



根据上图不难看出,“翻页区间切割(或称划分)”是把已知总页数划分为N段(n1, n2, ...),每段容纳M(m1, m2,...)个页链接,每个页链接对应一页,由数字编号。这里,我们讨论的“切割”是一个动态过程,而这个动态过程可以建立在静态“划分”的基础上。

在遭遇典型的大数据量和有限的屏幕空间时,翻页区间作为精确的导航系统是必不可少的,它应具备某些固定的属性和智能行为来辅助和引导用户浏览。我们应先针对屏幕显示空间的大小做划分,即给定翻页区间的长度$displaySize(图中Google搜索结果页区间长度是20)。然后我们便可以根据当前显示页$currentPage来动态地切割出它所在的区间范围(图中Google当前显示页是18),须做到让$currentPage处于区间起止页号所包含的范围内。同时,还要确保每次切割是在合理的范围内,不会出现页号溢出的现象,这就需要做一些后续的判断来达到智能化。

现代Web应用程序要求快速响应用户的请求,开发者往往要在用户体验和性能之间做出平衡。翻页区间切割算法首要考虑性能,因为我们主要剖析的是算法本身(貌似是废话 )。下面我们就结合PHP实现的代码来看看,如何做到切割的精确和性能最佳化。

代码清单 翻页区间切割算法
/**
* 获得页区间页号
*
* @param int $currentPage 当前页号
* @param int $totalPages 总页数
* @param int $displaySize 区间容量,默认显示10页
* @return array 返回由区间页号组成的数组
*/
function getPageRange($currentPage, $totalPages, $displaySize = 10) {
    if ($totalPages <= 0 || $displaySize <= 0) {
        return array();
    } elseif ($displaySize > $totalPages) {
        $startPage = 1;
        $endPage = $totalPages;
    } else {
        if ($currentPage % $displaySize === 0) {
            $startPage = $currentPage - $displaySize + 1;
        } else {
            while (($currentPage % $displaySize)) {
                --$currentPage;
            }
            $startPage = $currentPage + 1;
        }
        if ($startPage <= 0) {
            $startPage = 1;
        }
        $endPage = $startPage + $displaySize - 1;
        if ($endPage > $totalPages) {
            $endPage = $totalPages;
            $startPage = $endPage - $displaySize + 1;
        }
    }
    return range($startPage, $endPage);
}函数getPageRange接受三个参数,当前页$currentPage,总页数$totalPages,和翻页区间长度$displaySize,默认是10。根据这三个参数,函数getPageRange会生成一个适当的包含了$currentPage的翻页区间。首先,我们需要排除非法的参数值,对于总页数或区间长度小于零的情况,须加以检查。

然后,我们考察静态划分的思路。如前所述,给定翻页区间长度后,便可用总页数除以长度,得到区间个数。与此同时,我们可分析得知并不是所有区间都含有相同的页数,在极端情况下,还会出现总页数小于给定的翻页区间长度,那么划分或切割的结果将永远只有一个区间。幸运的是,这不会给我们的核心算法带来什么干扰,但我们仍须重视代码的健壮性。所以,我们先考虑极端情况,在运用算法解决核心问题之前,先迅速捕捉只有一页的区间。

接下来,我们便可以看看区间的固有属性了。每个动态切割的区间,都有一个起始页和一个尾页;由于区间彼此存在先后顺序,所以在经过静态划分后,我们始终会得到第一个(首)区间和最后一个(尾)区间,若首尾区间重合,则说明总页数小于给定的翻页区间长度。无论如何,算法需要解决的关键问题是如何找到区间的起始页和尾页,一旦确定这两个元素,便可以使用PHP内置的range函数生成区间内的全部页码。

算法利用当前页$currentPage和翻页区间长度$displaySize做比较,来判断当前页在区间内所处的位置,进而推导出区间起始页和尾页与当前页的偏移量。为了做到完美无缺,我们还要考虑边界溢出的问题,这也非常简单,只需判断起始页和尾页是否介于1和总页数之间即可。

至此,对于代码的分析已经完成。我们来看一下算法的时间效率,通俗地说,算法中的基本操作是求模,算法的执行时间取决于$currentPage与$displaySize的差值,差值越大,则求模次数越多、执行时间越长,呈线性结构。而实际的执行结果则是在瞬间完成的。

下面,我们来结合上面的Google搜索结果页,利用getPageRange函数生成一个翻页区间,输入所需参数:
print_r(implode(',', getPageRange(18, 27, 20)));得到的结果是:
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20大家会发现这和Google搜索结果页显示的完全不一样。对,因为Google的翻页区间把当前页强制设置在中间位置上了!嗯,不要灰心,我们仍可以利用getPageRange函数得到与之相匹配的结果,只需把问题再分解一下:
print_r(implode(',', array_merge(getPageRange(17, 17, 10), getPageRange(27, 27, 10))));得到的结果是:
8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27

作者: davidkoree   发布时间: 2009-02-19

很好  学习

作者: okjoyel   发布时间: 2009-02-23

相当好,学习了

作者: qxhy123   发布时间: 2009-02-23

很好~~~

作者: iamvalen   发布时间: 2009-02-24

学习了,呵呵,支持下

作者: libailin   发布时间: 2009-02-24

正好需要用,过来学习

作者: 0451229   发布时间: 2009-12-03