開始對資料結構的學習
今天寫程式碼換了一個字型,以前一直用console
很好看,今天發現一個更喜歡的風格Source Code Pro
上兩張圖,還是挺好看的!!!
步入正題,講講連結串列的操作
節點
- 首先得有一個節點類,用於儲存資料
<?php
namespace LinkedList;
class Node
{
/**
* @var $data integer
*/
public $data;
/**
* 節點指向的下一個元素
*
* @var $next Node
*/
public $next;
public function __construct(int $data = -1)
{
public function __construct(int $data = null)
{
// 初始化賦值 data,也可通過 $node->data = X; 賦值
$this->data = $data;
}
}
複製程式碼
連結串列管理類(用於操作節點資料)
- 操作類的程式碼由於太長,我們分部分解析
頭插入(因為比較簡單,所以先講這個)
- 聽名字,就知道是從頭部插入一個節點
- 當連結串列為空,則初始化當前節點
- 當連結串列不為空,把新節點作為頭結點
public function insertHead(int $data) : bool
{
///////////////////////////////////////////////////////////////////////////
// +-----------+ +--------+ +--------+
// | | | | | |
// | head node | +> | node | +> | node | +>
// | | | | | | | | |
// | | | | | | | | |
// | next | | | next | | | next | |
// +------+----+ | +----+---+ | +----+---+ |
// | | | | | |
// +------+ +-----+ +-----+
///////////////////////////////////////////////////////////////
// +-----------+ +--------+ +--------+
// | | | | | |
// +---> | head node | +> | node | +> | node | +>
// | | | | | | | | | |
// | | | | | | | | | |
// | | next | | | next | | | next | |
// | +------+----+ | +----+---+ | +----+---+ |
// | | | | | | |
// +--------+ | +------+ +-----+ +-----+
// | | |
// |new node| |
// | | |
// | | |
// | next | |
// +----+---+ |
// | |
// +-----+
//
// 1. 例項化一個資料節點
// 2. 使當前節點的下一個等於現在的頭結點
// 即使當前頭結點是 null,也可成立
// 3. 使當前節點成為頭結點
// 即可完成頭結點的插入
$newNode = new Node($data);
$newNode->next = $this->head;
$this->head = $newNode;
return true;
}
複製程式碼
插入節點(index=0 是頭結點,依次下去,超出位置返回 false)
public function insert(int $index = 0, int $data) : bool
{
// 頭結點的插入, 當頭部不存在,或者索引為0
if (is_null($this->head) || $index === 0) {
return $this->insertHead($data);
}
// 正常節點的插入, 索引從 0 開始計算
// 跳過了頭結點,從 1 開始計算
$currNode = $this->head;
$startIndex = 1;
// 遍歷整個連結串列,如果當前節點是 null,則代表到了尾部的下一個,退出迴圈
for ($currIndex = $startIndex; ! is_null($currNode); ++ $currIndex) {
////////////////////////////////////////////////////////////////////////////
///
// +--------+ +--------+ +-------------+ +--------+
// | | | | | | | |
// | node | +> |currNode| +> |currNode next| +> | node | +>
// | | | | | | | | | | | |
// | | | | | | | | | | | |
// | next | | | next | | | next | | | next | |
// +----+---+ | +----+---+ | +------+------+ | +----+---+ |
// | | | | | | | |
// +-----+ +-----+ +--------+ +-----+
////////////////////////////////////////////////////////////////////////////
// +--------+ +--------+ +-------------+ +--------+
// | | | | | | | |
// | node | +> |currNode| +> |currNode next| +> | node | +>
// | | | | | | | | | | | |
// | | | | | | | | | | | |
// | next | | | next | | | next | | | next | |
// +----+---+ | +--------+ | +------+------+ | +----+---+ |
// | | +--------+ | | | | |
// +-----+ | | | +--------+ +-----+
// |new node| |
// | | |
// | | |
// | next | |
// +----+---+ |
// | |
// +-----+
////////////////////////////////////////////////////////////////////////////
//
// +--------+ +--------+ +-------------+ +--------+
// | | | | | | | |
// | node | +> |currNode| +> |currNode next| +> | node | +>
// | | | | | | | | | | | |
// | | | | | | | | | | | |
// | next | | | next | | | next | | | next | |
// +----+---+ | +----+---+ | +------+------+ | +----+---+ |
// | | | +--------+ | | | | |
// +-----+ | | | | +--------+ +-----+
// +----> |new node| |
// | | |
// | | |
// | next | |
// +----+---+ |
// | |
// +-----+
//
// 1. 當前索引等於傳入引數的索引
// 2. 例項化新資料節點
// 3. 新節點的下一個指向當前節點的下一個節點
// 4. 當前節點的下一個節點指向新節點
if ($currIndex === $index) {
$newNode = new Node($data);
$newNode->next = $currNode->next;
$currNode->next = $newNode;
return true;
}
// 移動到下一個節點
$currNode = $currNode->next;
}
return false;
}
複製程式碼
以上兩個這是插入的基本操作。看一下例項的程式碼。
<?php
// 自動載入的程式碼就不貼了,直接在 github
require __DIR__.'/../vendor/bootstrap.php';
// 例項化一個連結串列管理物件
$manager = new \LinkedList\Manager();
// 8
$manager->insertHead(8);
// 5 8
$manager->insertHead(5);
// 1 5 8
$manager->insertHead(1);
// 1 2 5 8
$manager->insert(1, 2);
// false 節點元素不足 6 個
$manager->insert(5, 4);
// 1 2 5 8 9
$manager->insertEnd(9);
// 3
$manager->find(8);
// 1 2 8 9
$manager->delete(2);
複製程式碼
查詢
- 查詢連結串列的值也是很簡單的,只要遍歷即可
/**
* 查詢連結串列的值中的索引
* 成功返回索引值,找不到返回 -1
*
* @param int $data
* @return int
*/
public function find(int $data) : int
{
$currNode = $this->head;
// 查詢還是很簡單的,只要遍歷一次連結串列,然後再判斷值是否相等就可以了
for ($i = 0; ! is_null($currNode); ++ $i) {
if ($currNode->data === $data) {
return $i;
}
$currNode = $currNode->next;
}
return -1;
}
複製程式碼
- 只需要遍歷一次連結串列,找到相等的值,找到返回索引值,找不到返回 -1
刪除
/**
* 刪除連結串列的節點
*
* @param int $index
* @return bool
*/
public function delete(int $index) : bool
{
// 沒有任何節點,直接跳過
if (is_null($this->head)) {
return false;
} elseif ($index === 0) {
// 頭結點的刪除
$this->head = $this->head->next;
}
// 這裡的開始的索引是 1
// 但當前節點指向的確實 頭結點
// 因為刪除的時候必須標記刪除的前一個節點
// for 的判斷是判斷下一個節點是否為 null
// $currNode 是操作的節點
// $currNode->next 是要刪除的節點
$startIndex = 1;
$currNode = $this->head;
for ($i = $startIndex; ! is_null($currNode->next); ++ $i) {
if ($index === $i) {
// 使當前節點等於要刪除節點的下一個
// 即可完成刪除
$currNode->next = $currNode->next->next;
break;
}
$currNode = $currNode->next;
}
return true;
}
複製程式碼
End
- 程式碼已託管在github
- 後續有時間繼續學習資料結構,雙連結串列,樹之類的!!!