《数据结构 : 静态单链表 (C++ 描述)》中讲过, 静态单链表主要是面向没有指针的语言, PHP 就是一个很好的例子. 不过, PHP 中是存在引用 "&" 的, 所以改造代码变得非常简单

实战中将会用到的 PHP 语法 :

  • 面向对象编程 (接口、继承、修饰符、属性与方法、父类调用)
  • 数组
  • 引用
  • 条件判断
  • 循环
  • 命名空间

初次之外, 还有文件的包含和系统自带的函数

其中, 接口和命名空间是之前没有讲过的, 这个在之后会有

这里就不再累赘具体思路, 因为之前的文章已经详细讲过了, 直接给出代码 :

StaticLinkedListInterface.php :

<?php
   namespace Jonny\StaticLinkedList;
   interface NodeInterface {
      public function getData();
      public function getCursor();
      public function insertData($data);
      public function insertCursor($cursor);
   }
   interface LinkListInterface extends NodeInterface {
      public function __construct($maxSize);
      public function __destruct();
      public function getElement($position);
      public function getLength();
      public function insert($data, $position);
      public function insertFromHead($data);
      public function insertFromTail($data);
      public function locate($data);
      public function locateAllData($data);
      public function deleteByPosition($position);
      public function deleteByElement($data);
      public function cleanList();
      public function getStaticList();
   }
?>

StaticLinkedList.php

<?php
   use Jonny\StaticLinkedList;
   require_once("StaticLinkedListInterface.php");
   class Node implements StaticLinkedList\NodeInterface{
      protected const cursorLast = -1;
      protected const cursorEmpty = -2;
      protected $data;
      protected $cursor;
      public function getData() {
         return $this->data;
      }
      public function getCursor() {
         return $this->cursor;
      }
      public function insertData($data) {
         $this->data = $data;
      }
      public function insertCursor($cursor) {
         $this->cursor = $cursor;
      }
   }
   class LinkList extends Node implements StaticLinkedList\LinkListInterface {
      private $usedSize;
      private $insertPointer;
      private $first;
      protected $staticList;
      protected $maxSize;
      public function __construct($maxSize) {
         $this->maxSize = $maxSize;
         $this->staticList = array();
         $this->usedSize = 0;
         for($i = 1; $i <= $maxSize; $i++) {
            $this->staticList[$i] = new Node();
                $this->staticList[$i]->insertCursor(Parent::cursorEmpty);
         }
         $this->staticList[0] = new Node();
         $this->first = &$this->staticList[0];
         $this->insertPointer = &$this->staticList[1];
         $this->first->insertCursor(Parent::cursorLast);
      }
      public function __destruct() {
         unset($this->usedSize, $this->insertPointer, $this->first, $this->staticList, $this->maxSize);
      }
        protected function insertPointerFind() {
            $flag = false;
            for($i = 1; $i <= $this->maxSize; $i++) {
                if($this->staticList[$i]->getCursor() == Parent::cursorEmpty) {
                    $this->insertPointer = &$this->staticList[$i];
                    $flag = true;
                    break;
                }
            }
            if(!$flag) {
                $this->insertPointer = false;
            }
        }
        protected function getInsertPointerIndex() {
            for($i = 1; $i <= $this->maxSize; $i++) {
                if($this->insertPointer == $this->staticList[$i]) {
                    return $i;
                }
            }
        }
      public function getElement($position) {
         if($position < 1 or $position > $this->usedSize) {
            return false;
         }
         $linkList = &$this->first;
         $count = 0;
         while($count != $position) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            $count++;
         }
         return $linkList->getData();
      }
      public function getLength() {
         return $this->usedSize;
      }
      public function insert($data, $position) {
         if(!$this->insertPointer) {
            return false;
         }
         $linkList = &$this->first;
         $count = 0;
         while($count != $position - 1) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            $count++;
         }
         $this->insertPointer->insertData($data);
         if($linkList->getCursor() != Parent::cursorLast) {
            $this->insertPointer->insertCursor($linkList->getCursor());
            $linkList->insertCursor($this->getInsertPointerIndex());
         }else {
            $this->insertPointer->insertCursor(Parent::cursorLast);
            $linkList->insertCursor($this->getInsertPointerIndex());
         }
         $this->usedSize++;
         $this->insertPointerFind();
      }
      public function insertFromHead($data) {
         if(!$this->insertPointer) {
            return false;
         }
         $this->insertPointer->insertData($data);
         $linkList = &$this->first;
         if($linkList->getCursor() == Parent::cursorLast) {
            $linkList->insertCursor($this->getInsertPointerIndex());
            $this->insertPointer->insertCursor(Parent::cursorLast);
            $this->usedSize++;
            $this->getInsertPointerIndex();
            return null;
         }
         $this->insertPointer->insertCursor($linkList->getCursor());
         $linkList->insertCursor($this->getInsertPointerIndex());
         $this->usedSize++;
         $this->insertPointerFind();
      }
      public function insertFromTail($data) {
         if(!$this->insertPointer) {
            return false;
         }
         $this->insertPointer->insertData($data);
         $linkList = &$this->first;
         while($linkList->getCursor() != Parent::cursorLast) {
            $linkList = &$this->staticList[$linkList->getCursor()];
         }
         $linkList->insertCursor($this->getInsertPointerIndex());
         $this->insertPointer->insertCUrsor(Parent::cursorLast);
         $this->insertPointerFind();
         $this->usedSize++;
      }
      public function locate($data) {
         $linkList = &$this->first;
         $count = 0;
         while($linkList->getCursor() != Parent::cursorLast) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            $count++;
            if($linkList->getData() == $data) {
               return $count;
            }
         }
         return false;
      }
      public function locateAllData($data) {
         $linkList = &$this->first;
         $count = 0;
         while($linkList->getCursor() != Parent::cursorLast) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            if($linkList->getData() == $data) {
               $count++;
            }
         }
         if(!$count) {
            return false;
         }
         $location = array();
         $linkList = &$this->first;
         $count = 1;
         $loopCount = 0;
         while($linkList->getCursor() != Parent::cursorLast) {
            $loopCount++;
            if($this->staticList[$linkList->getCursor()]->getData() == $data) {
               $location[$count] = $loopCount;
               $count++;
            }
            $linkList = &$this->staticList[$linkList->getCursor()];
         }
         $location[0] = $count - 1;
         return $location;
      }
      public function deleteByPosition($position) {
         if($position < 1 or $position > $this->usedSize) {
            return false;
         }
         $linkList = &$this->first;
         $count = 0;
         while($count != $position - 1) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            $count++;
         }
         $node = &$this->staticList[$linkList->getCursor()];
         if($node->getCursor() != Parent::cursorLast) {
            $linkList->insertCursor($node->getCursor());
            $node->insertCursor(Parent::cursorLast);
         }else {
            $linkList->insertCursor(Parent::cursorLast);
            $node->insertCursor(Parent::cursorEmpty);
         }
         $this->usedSize--;
         $this->insertPointerFind();
      }
      public function deleteByElement($data) {
         if($this->locate($data) === false) {
            return false;
         }
         while($this->locate($data)) {
            $linkList = &$this->first;
            while($linkList->getCursor() != Parent::cursorLast) {
               if($this->staticList[$linkList->getCursor()]->getData() == $data and $this->staticList[$linkList->getCursor()]->getCursor() != Parent::cursorLast) {
                  $node = &$this->staticList[$linkList->getCursor()];
                  $linkList->insertCursor($node->getCursor());
                  $node->insertCursor(Parent::cursorEmpty);
                  $this->usedSize--;
               }else if($this->staticList[$linkList->getCursor()]->getData() == $data and $this->staticList[$linkList->getCursor()]->getCursor() == Parent::cursorLast) {
                  $node = &$this->staticList[$linkList->getCursor()];
                  $linkList->insertCursor(Parent::cursorLast);
                  $node->insertCursor(Parent::cursorEmpty);
                  $this->usedSize--;
               }
               $linkList = &$this->staticList[$linkList->getCursor()];
            }
         }
         $this->insertPointerFind();
      }
      public function cleanList() {
         $linkList = &$this->first;
         $linkList = &$this->staticList[$linkList->getCursor()];
         while($linkList->getCursor() != Parent::cursorLast) {
            $node = &$linkList;
            $linkList = &$this->staticList[$linkList->getCursor()];
            $node->insertCursor(Parent::cursorEmpty);
         }
         $linkList->insertCursor(Parent::cursorEmpty);
         $this->first->insertCursor(Parent::cursorLast);
         $this->usedSize = 0;
         $this->insertPointerFind();
      }
      public function getStaticList() {
         $list = array();
         $linkList = &$this->first;
         while($linkList->getCursor() != Parent::cursorLast) {
            $linkList = &$this->staticList[$linkList->getCursor()];
            $list[count($list)] = $linkList->getData();
         }
         return $list;
      }
   }
?>

以上代码在 PhpStorm 里面是测试通过的

这里主要讲一下遇到的坑

这次是本人第一次使用 PHP 进行面向对象编程, 幸亏有 PhpStorm, 否则很多错误都是莫名其妙

  1. 当类别中需要调用自己的属性以及方法, 需要在前面加上 "$this->". 前段时间 C++ 写多了, 没怎么看 PHP, 导致自己花了一段时间去修改这个错误
  2. 子类调用父类中属性或者方法可以在前面加上 "Parent::"
  3. PHP 暂时不支持多重继承, 有些时候可以使用性状 (traits), 本篇没有用到

本来想做一个简单的网页, 插在这篇文章里面, 实现网页静态单链表. 但是在 JavaScript 与 AJAX 调用 PHP 的时候出现了错误, 具体错误暂时没有找到. 从 Safari 网路这里看返回了 500 错误, 应该是服务器那边的问题. 这个问题解决还需要一段时间, 因为最近要考试, 没办法太关注这个了

如果之后做出来了, 可能会出个 JavaScript 的教程