一次请求对多条数据进行排序的算法(一)

序号order从1开始的递增整数,无间断无重复

为保证序号不间断、无重复,每次修改数据的序号后,都要对其他的数据序号进行顺移。
同时移动多条数据是指保证序号不间断、无重复的情况下,一次请求中:之后的数据移动不影响之前移动过的数据的序号。
移动流程:

把数据块从位置o移动到位置n,并添加1个锁定块和1个预留位(预留位=n),锁定块不再参与移动
如果o>n:区域上移
    把m和n(包括m、n)之间的数据(排除锁定块)下移1位
    把预留位的数据下移1位,执行c次(c=预留位数量-1)
如果o<n:区域下移
    把m和n(包括m、n)之间的数据(排除锁定块)上移1位
    把预留位的数据上移1位,执行c次(c=预留位数量-1)
重复上面的步骤,直到所有数据被移动到指定的位置

示意图:

去重说明:每移动一次会产生一个预留位,下次区域顺移的时候可能会有数据被移动到预留位,这时候需要再次移动预留位上的数据,但是如果有多条相邻的预留位,移动后还是在预留位上,所以最多需要移动c次,c=预留位数量-1。

下面是一个php实例:

//要移动的数据
$rows = array(
    array(
        "id"=>3,/*唯一标识*/
        "moveto"=>8/*目标位置*/
    ),
    array(
        "id"=>4,
        "moveto"=>9
    ),
    array(
        "id"=>12,
        "moveto"=>2
    )
    ...
)
$locked = array();//锁定块数组
$lockedorder = array();//预留位数组
foreach($rows as $row){
    $o = $db->result("SELECT order FROM ".DB_TABLEPRE."user WHERE  id=$row[$id] ");//数据原来的位置o
    $n = $row[moveto];//目标位置n
    $db->query("update user set order=$n  WHERE  id=".$row[$id]);//移动该条数据
   
    if($n == $o){
        //不用移动
    }elseif($n > $o){
        //区域上移
        $db->query("update user set order=order-1  WHERE  id NOT IN(implode(',',$locked))  AND order>=$o AND order<=$n ");
        //执行c次排重
        foreach($locked as $temp){
            $db->query("update user set order=order-1  WHERE  id NOT IN(implode(',',$locked))  AND order>=$from AND order<=$n  AND order IN(implode(',',$lockedorder))");
        } 
    }else{
        //区域下移
        $db->query("update user set order=order+1  WHERE  id NOT IN(implode(',',$locked))  AND order<=$o AND order>=$n ");
        //执行c次排重
        foreach($locked as $temp){
            $db->query("update user set order=order+1  WHERE  id NOT IN(implode(',',$locked))  AND order<=$o AND order>=$n AND order IN(implode(',',$lockedorder))");
        } 
    }
    $locked [] = $row[$id];//添加一个锁定数据块
    $lockedorder [] = $n;//添加一个预留位
}

 

posted @ 2016-12-23 17:22  godok  阅读(797)  评论(0编辑  收藏  举报