一次请求对多条数据进行排序的算法(一)
序号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;//添加一个预留位 }