PHP 链表结构之环型链表(三)

php链表结构 环型链表(三)

环型链表结构,我们这边的环型链表其实和双向链表相似,就是最后一个节点指向了我们的开始节点上,我们这边定义一个节点类,属性有当前值(data)和指向下一个节点的(next), 和指向上一个节点的(previous)。

class Node {
    public $data;
    public $next;
    public $previous;

    public function __construct($data)
    {
        $this->data = $data;
    }
}

之后是链表结构类 ,我们定义一个头节点,以头节点开始,next指向下一个节点,previous指向上一个节点,具体看情况添加你所需要的其他属性,并且将最后一个节点的next指向第一个节点

class LoopLinkedList
{
    private $headList;

    public function __construct($data)
    {
        $this->headList = new Node($data);
        $this->headList->next = $this->headList;
        $this->headList->previous = $this->headList;
    }
}
1. 往链表中插入一个值(尾部插入)
public function insert($data) {
    $currentNode = $this->headList;
    while ($currentNode->next !== $this->headList) {
        $currentNode = $currentNode->next;
    }
    $newNode = new Node($data);
    $currentNode->next = $newNode;
    $newNode->previous = $currentNode;
    $newNode->next = $this->headList;
    $this->headList->previous = $newNode;
}
$loop_link = new LoopLinkedList(1);
$loop_link->insert(2);
$loop_link->insert(3);
var_dump($loop_link);
结果:
object(LoopLinkedList)#1 (1) {
  ["headList":"LoopLinkedList":private]=>
  object(Node)#2 (3) {
    ["data"]=>
    int(1)
    ["next"]=>
    object(Node)#3 (3) {
      ["data"]=>
      int(2)
      ["next"]=>
      object(Node)#4 (3) {
        ["data"]=>
        int(3)
        ["next"]=>
        *RECURSION*
        ["previous"]=>
        *RECURSION*
      }
      ["previous"]=>
      *RECURSION*
    }
    ["previous"]=>
    object(Node)#4 (3) {
      ["data"]=>
      int(3)
      ["next"]=>
      *RECURSION*
      ["previous"]=>
      object(Node)#3 (3) {
        ["data"]=>
        int(2)
        ["next"]=>
        *RECURSION*
        ["previous"]=>
        *RECURSION*
      }
    }
  }
}
2. 查询链表中的某个节点
public function find($query) {
    $currentNode = $this->headList;
    if ($currentNode->next === $this->headList) {
        if ($currentNode->data == $query) {
            return $currentNode;
        } else {
            return NULL;
        }
    }

    $flag = false;
    while ($currentNode->next !== $this->headList) {
        if ($currentNode->data == $query) {
            $flag = true;
            return $currentNode;
        }
        $currentNode = $currentNode->next;
    }

    if ($currentNode->next === $this->headList && !$flag) {
        if ($currentNode->data == $query) {
            return $currentNode;
        }
    }
    return NULL;
}
$loop_link = new LoopLinkedList(1);
$loop_link->insert(2);
$loop_link->insert(3);
$result = $loop_link->find(2);
var_dump($result);
结果: 
object(Node)#3 (3) {
  ["data"]=>
  int(2)
  ["next"]=>
  object(Node)#4 (3) {
    ["data"]=>
    int(3)
    ["next"]=>
    object(Node)#2 (3) {
      ["data"]=>
      int(1)
      ["next"]=>
      *RECURSION*
      ["previous"]=>
      *RECURSION*
    }
    ["previous"]=>
    *RECURSION*
  }
  ["previous"]=>
  object(Node)#2 (3) {
    ["data"]=>
    int(1)
    ["next"]=>
    *RECURSION*
    ["previous"]=>
    object(Node)#4 (3) {
      ["data"]=>
      int(3)
      ["next"]=>
      *RECURSION*
      ["previous"]=>
      *RECURSION*
    }
  }
}
3. 删除链表中的指定值的节点(不过有个特殊点,该方法返回的是删除节点的下一个节点,后续实战例子将使用到)
public function display($data) {
    $currentNode = $this->headList;

    $flag = false;
    //只有一个节点的情况
    if ($currentNode->next == $this->headList) {
        if ($currentNode->data == $data) {
            $flag = true;
            $this->headList = NULL;
            return NULL;
        }
    }

    //开始节点到最后节点,不包括最后一个节点
    while ($currentNode->next !== $this->headList && !$flag) {
        if ($currentNode->data == $data) {
            $flag = true;
            $upPointer = $currentNode->previous;
            $downPointer = $currentNode->next;
            $currentNode->next->previous = $upPointer;
            $currentNode->previous->next = $downPointer;
            return $currentNode->next;
        }
        $currentNode = $currentNode->next;
    }

    //处理最后一个节点
    if ($currentNode->data = $data && !$flag) {
        $upPointer = $currentNode->previous;
        $downPointer = $currentNode->next;
        $currentNode->next->previous = $upPointer;
        $currentNode->previous->next = $downPointer;
        return $currentNode->next;
    }
}
$loop_link = new LoopLinkedList(1);
$loop_link->insert(2);
$loop_link->insert(3);
$Node = $loop_link->display(2);
var_dump($Node);
结果:
object(Node)#4 (3) {
  ["data"]=>
  int(3)
  ["next"]=>
  object(Node)#2 (3) {
    ["data"]=>
    int(1)
    ["next"]=>
    *RECURSION*
    ["previous"]=>
    *RECURSION*
  }
  ["previous"]=>
  object(Node)#2 (3) {
    ["data"]=>
    int(1)
    ["next"]=>
    *RECURSION*
    ["previous"]=>
    *RECURSION*
  }
}

至于还有别的方式,本次就不再一一介绍,接下来给大家一个实战例子

学校中经典常用到的,一群学生有各自的标号,围成一圈,一个红领巾将交给开始的学生,从这名开始学生开始计数之后每过3人,则将拿到红领巾的学生剔除,最终剩下的人一一约瑟夫环问题

约瑟夫环处理方式
//通过开始位置与偏移量,获取最后剩下的节点
public function getLastSurvivalNode($offset, $query = NULL) {
    $position = 1;

    if ($query == NULL) {
        $queryNode = $this->headList;
    } else {
        //指定位置
        $queryNode = $this->find($query);
        if ( is_null($queryNode) ) {
            echo "查询开始节点失败".PHP_EOL;
            return;
        }
    }

    while ( $queryNode->next != $queryNode ) {
        if ($position == $offset) {
            $queryNode = $this->display($queryNode->data);
            $position = 1;
        }
        $queryNode = $queryNode->next;
        $position++;
    }

    return $queryNode;
}
$loop_link = new LoopLinkedList(1);
$loop_link->insert(2);
$loop_link->insert(3);
$loop_link->insert(4);
$loop_link->insert(5);
$lastNode = $loop_link->getLastSurvivalNode(3);
var_dump($lastNode);
结果: 
object(Node)#5 (3) {
  ["data"]=>
  int(4)
  ["next"]=>
  *RECURSION*
  ["previous"]=>
  *RECURSION*
}

上一篇:PHP 链表结构之双链表(二)

author: clown
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容