我正在用PHP写一个小算法,通过 n 数量的电影评级,并存储前5个。我不是从数据文件中读取,而是从流中读取我不能简单地通过评级来订购电影。
我的问题是,当我阅读流时,跟踪前5部评级电影最有效的方法是什么?目前我做以下事情:
我的方法有效,但每次阅读后都需要对列表进行排序。我认为这是一种昂贵的方法,主要是因为我每次使用array_multisort()时都必须对5部电影进行for循环,以构建索引进行排序。任何人都可以建议更好的方法来解决这个问题吗?
答案 0 :(得分:4)
链接列表可以在这里使用。
构建一个链接列表,以正确的顺序链接前5部电影。对于每部新电影,只需从链的末尾开始,直到电影介于评分较高且评分较低的电影之间。然后将链接插入此处的列表中。如果电影好于最差(因此你的列表现在是6长),只需删除链中的最后一个链接,然后你又回到5。
没有排序,没有索引。
答案 1 :(得分:3)
你的算法看起来很好。我不确定如何在PHP中实现数组。从算法的角度来看:使用堆而不是数组。
答案 2 :(得分:3)
每次阅读后重新排序都没有意义,因为你真的只需要插入一个新条目。使用以下算法,它可能会让您获得最佳速度。它基本上是一个展开的循环,而不是最漂亮的代码。
set movies[0..4].rating to -1.
while more movies in stream:
read in next movie.
if movie.rating < movies[0].rating:
next while
if movie.rating < movies[1].rating:
movies[0] = movie
next while
if movie.rating < movies[2].rating:
movies[0] = movies[1]
movies[1] = movie
next while
if movie.rating < movies[3].rating:
movies[0] = movies[1]
movies[1] = movies[2]
movies[2] = movie
next while
if movie.rating < movies[4].rating:
movies[0] = movies[1]
movies[1] = movies[2]
movies[2] = movies[3]
movies[3] = movie
next while
movies[0] = movies[1]
movies[1] = movies[2]
movies[2] = movies[3]
movies[3] = movies[4]
movies[4] = movie
最后,您有已分类的电影列表。如果小于5,则其他人的评分为-1,因此您将知道它们无效。这假设真实电影的评级为零或更高,但如果不是,则可以调整这些值。
如果你需要为超过5部电影调整它,你可以。最好的选择是再次卷起循环。但是,在某些时候,对它进行排序比使用这种方法更有效。这种方法仅适用于小型数据集。
答案 3 :(得分:1)
我的方法有效,但每次阅读后都需要对列表进行排序。
不,它没有,它只需要你找到一个评级为&gt;的新电影后排序。动画[0] [评分]。
这种方法对我来说似乎很有效。你只会偶然排序前5名的新参赛作品,你所处理的电影数量会减少。
答案 4 :(得分:0)
名单有多大?我猜这不是一个选项,可以将整个列表保存在内存中,并在最后对其进行排序?
答案 5 :(得分:0)
答案 6 :(得分:0)
这就是我要做的事情:
// let’s say get_next_movie () returns array with 'rating' and 'name' keys
while ($m = get_next_movie ()) {
$ratings[$m['rating']][] = $m['movie'];
$temp_ratings = $ratings;
$top5 = array ();
$rating = 5;
while (1) {
if (count ($temp_ratings[$rating])) {
$top5[] = array_shift ($temp_ratings[$rating]);
} elseif ($rating > 0) {
--$rating;
} else {
break;
}
}
// $top5 has current top 5 :-)
}
$ ratings数组看起来像这样,每个评级都包含一系列电影:
Array
(
[5] => Array
(
[0] => Five!
)
[3] => Array
(
[0] => Three
[1] => Threeeeee
[2] => Thr-eee-eee
)
[4] => Array
(
[0] => FOR
)
)
答案 7 :(得分:0)
也许这会有所帮助。
class TopList {
private $items = array();
private $indexes = array();
private $count = 0;
private $total = 5;
private $lowest;
private $sorted = false;
public function __construct($total = null) {
if (is_int($total))
$this->total = $total;
$this->lowest = -1 * (PHP_INT_MAX - 1);
}
public function addItem($index, $item) {
if ($index <= $this->lowest)
return;
$setLowest = $this->count === $this->total;
if ($setLowest) {
/* //remove first added
$lowestIndex = array_search($this->lowest, $this->indexes);
/*/ //remove last added
$lowestIndex = end(array_keys($this->indexes, $this->lowest));
//*/
unset($this->indexes[$lowestIndex], $this->items[$lowestIndex]);
} else {
++$this->count;
$setLowest = $this->count === $this->total;
}
$this->indexes[] = $index;
$this->items[] = $item;
$this->sorted = false;
if ($setLowest)
$this->lowest = min($this->indexes);
}
public function getItems() {
if (!$this->sorted) {
array_multisort($this->indexes, SORT_DESC, $this->items);
$this->sorted = true;
}
return $this->items;
}
}
$top5 = new TopList(5);
foreach ($movies as $movie) {
$top5->addItem($movie['rating'], $movie);
}
var_dump($top5->getItems());