Я пытаюсь реализовать список пропусков в PHP, используя псевдокод из http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/Map/skip-list-impl.html. Мне удалось заставить его работать нормально в Java, но не в PHP. Мой метод put всегда возвращает ноль, и поэтому мой метод get тоже возвращает ноль.
Я не совсем понимаю, где я иду не так, поэтому я был бы признателен за любую помощь!
<?php
interface SkipListEntry {
public function getPrev();
public function getNext();
public function getAbove();
public function getBelow();
public function getKey();
public function getValue();
public function setValue($v);
public function setPrev($v);
public function setNext($v);
public function setAbove($v);
public function setBelow($v);
public function hasPrev();
public function hasNext();
public function hasAbove();
public function hasBelow();
}
class SkipListNode implements SkipListEntry {
private $prev;
private $next;
private $above;
private $below;
private $key;
private $value;
public static $posInf = "+oo";
public static $negInf = "-oo";
function __construct($a, $b) {
$this->key = $a;
$this->value = $b;
}
public function getPrev(){
return $this->prev;
}
public function getNext(){
return $this->next;
}
public function getAbove(){
return $this->above;
}
public function getBelow(){
return $this->below;
}
public function getKey(){
return $this->key;
}
public function getValue(){
return $this->value;
}
public function setValue($n){
$this->value = $n;
}
public function setPrev($n) {
$this->prev = $n;
}
public function setNext($n) {
$this->next = $n;
}
public function setAbove($n) {
$this->above = $n;
}
public function setBelow($n) {
$this->below = $n;
}
public function hasPrev(){
return !is_null($this->prev);
}
public function hasNext(){
return !is_null($this->next);
}
public function hasAbove(){
return !is_null($this->above);
}
public function hasBelow(){
return !is_null($this->below);
}
}
class SkipList{
private $topLeft;
private $topRight;
private $height = 0;
private $totalEntries = 0;
private $head;
function __construct(){
$this->topLeft = new SkipListNode(SkipListNode::$negInf, null);
$this->topRight = new SkipListNode(SkipListNode::$posInf, null);
$this->topLeft->setNext($this->topRight);
$this->topRight->setPrev($this->topLeft);
$this->head = $this->topLeft;
}
public function size() {
return $this->totalEntries;
}
public function isEmpty(){
return $this->totalEntries == 0;
}
public function search($key){
$p = $this->head;
while (true) {
while (!$p->getNext()->getKey() == SkipListNode::$posInf
&& strcmp($p->getNext()->getKey(), $key) <= 0) {
$p = $p->getNext();
}
if ($p->hasBelow()){
$p = $p->getBelow();
}
else {
break;
}
}
return $p;
}
public function put($key, $value){
$searchElement = $this->search($key);
if ($key == $searchElement->getKey()){
$oldValue = $searchElement->getValue();
$searchElement->setValue($value);
return $oldValue;
}
$newEntry = new SkipListNode($key, $value);
$newEntry->setPrev($searchElement);
$newEntry->setNext($searchElement->getNext());
$searchElement->getNext()->setPrev($newEntry);
$searchElement->setNext($newEntry);
$currentHeight = 0;
for ($j = 1; $j <= $this->coinFlip(); $j ++){
if ($currentHeight >= $this->height){
$this->createAdditionalLayer();
}
while (is_null($searchElement->getAbove())){
$searchElement = $searchElement->getprev();
}
$searchElement = $searchElement->getAbove();
$aboveElement = new SkipListNode($key, null);
$aboveElement->setPrev($searchElement);
$aboveElement->setNext($searchElement->getNext());
$aboveElement->setBelow($newEntry);
$searchElement->getNext()->setPrev($aboveElement);
$searchElement->setNext($aboveElement);
$newEntry->setAbove($aboveElement);
$newEntry = $aboveElement;
$currentHeight ++;
}
$this->totalEntries ++;
return null;
}
public function get($key){
$p = $this->search($key);
if ($p->getKey() == $key){
return $p->getValue();
}
return null;
}
private function createAdditionalLayer(){
$newtopLeft = new SkipListNode(SkipListNode::$negInf, null);
$newtopRight = new SkipListNode(SkipListNode::$posInf, null);
$newtopLeft->setNext($newtopRight);
$newtopLeft->setBelow($this->head);
$newtopRight->setPrev($newtopLeft);
$this->head->setAbove($newtopLeft);
$this->head = $newtopLeft;
$this->height ++;
}
private function coinFlip(){
$total = 0;
$current = -1;
while ($current != 1){
$current = rand(0,1);
$total ++;
}
return $total;
}
}
// test
$a = new SkipList();
var_dump($a->put("a", "b"));
var_dump($a->put("a", "c")); // should return c (returns null)
var_dump($a->size()); // should return 1 (returns 2)
var_dump($a->get("a")); // should return c, (returns null)
Спасибо!
Я обнаружил некоторые проблемы в функции поиска:
пожалуйста, измените ваш код и попробуйте:
public function search($key){
$p = $this->head;
while (true) {
while ($p->getNext()->getKey() != SkipListNode::$posInf
&& strcmp($p->getNext()->getKey(), $key) == 0) {
$p = $p->getNext();
}
if ($p->hasBelow()){
$p = $p->getBelow();
}
else {
break;
}
}
return $p;
}
Результат:
var_dump($a->put("a", "b"));
var_dump($a->put("a", "c")); string 'b',
var_dump($a->size()); int 1,
var_dump($a->get("a")); string 'c'
Других решений пока нет …