摘要:因?yàn)樯婕爸羔槪覀冇靡脕砟M,所以讀者應(yīng)該有面向?qū)ο蟮闹R貯備。引文因?yàn)樯婕皟?nèi)存,常常會有一些程序的邊界限制,需要擁有一定嚴(yán)密的邏輯去保證代碼的魯棒性和健壯性,所以這個知識點(diǎn)是面試的常考點(diǎn)。
tips:因?yàn)樯婕爸羔槪覀冇靡脕砟M,所以讀者應(yīng)該有面向?qū)ο蟮闹R貯備。引子
你可以把鏈表簡單理解為動態(tài)數(shù)組,它不需要一塊一塊的開辟空間,同時,你又要注意,它存在的主要意義或者說使用場景主要是”指針功能“,它能夠指來指去,對一些應(yīng)用特別是內(nèi)存管理起到了關(guān)鍵作用。
引文因?yàn)樯婕皟?nèi)存,常常會有一些程序的邊界限制,需要programer擁有一定嚴(yán)密的邏輯去保證代碼的魯棒性和健壯性,所以這個知識點(diǎn)是面試的常考點(diǎn)。下面我們看看PHP的單鏈表實(shí)現(xiàn)(附常考題目實(shí)現(xiàn)):
data = $val; $this->next = $nex; } } /** * TODO:構(gòu)建單鏈表 */ Class SingleLinkList{ /* 頭插法創(chuàng)建鏈表 n為節(jié)點(diǎn)總數(shù) */ public function headInsert($n){ /* 新建一個頭節(jié)點(diǎn) */ $head = new Node(null,null); for($i=$n;$i>0;$i--){ $newNode = new Node($i,null); $head->data = $newNode->data; #新建節(jié)點(diǎn)賦值給頭節(jié)點(diǎn) $newNode->next = $head->next; #將頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)作為新建節(jié)點(diǎn)的后繼節(jié)點(diǎn),相當(dāng)于在原頭節(jié)點(diǎn)和頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)中間添加了一個新節(jié)點(diǎn) $head->next = $newNode; #將新建節(jié)點(diǎn)作為頭節(jié)點(diǎn)的后繼節(jié)點(diǎn),這時候原本頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)已經(jīng)改變了 } return $head; } /* 尾插法創(chuàng)建鏈表 */ public function rearInsert($n){ /* 新建一個尾節(jié)點(diǎn) */ $rear = new Node(null,null); for($j=0;$j<$n;$j++){ $newNode = new Node($j,null); $rear->data = $newNode->data; //$newNode = $rear->next; $rear->next = $newNode; $rear = $newNode; } return $rear; } /** * TODO:讀取鏈表中第i個數(shù)據(jù) * @param $list object 待插入的鏈表 * @param $i int 節(jié)點(diǎn)序號 */ public function readIThNode($list,$i){ /* 如果鏈表為空或者i小等于0 */ if($list == null || $i<=0){ echo "輸入?yún)?shù)不合法"; return ; } /* */ $p = $list->next; #設(shè)置p指向第一個節(jié)點(diǎn)(即頭節(jié)點(diǎn)的后繼節(jié)點(diǎn))) $j=0; #計(jì)時器必須初始化 while($p && $j<$i ){ $p = $p->next; ++$j; } /* 第i步 */ if($p == null){ #說明鏈表已經(jīng)結(jié)束,不存在i節(jié)點(diǎn),過濾掉i大于鏈表長度的情況(因?yàn)楣?jié)點(diǎn)是散列的,事先并不知道其長度) echo "i長度大于鏈表長度" ; exit; }else{ $e = $p->data; #第i個節(jié)點(diǎn)存在 ,返回 return $e; } } /** * TODO:在鏈表的第i個位置之前插入節(jié)點(diǎn)e * @param $list object 待插入的鏈表 * @param $i int 節(jié)點(diǎn)序號 * @param $e object 待插入的節(jié)點(diǎn) */ public function Insert($list,$i,$e){ if($e == null){ echo "待插入節(jié)點(diǎn)為空"; exit; } $p = $list->next; #設(shè)置p指向第一個節(jié)點(diǎn) $j=0; #計(jì)時器必須初始化 while($p && $j<$i ){ $p = $p->next; #保證節(jié)點(diǎn)在向后移動 ++$j; } /* 第i步 */ if($p == null){ #說明鏈表已經(jīng)結(jié)束,不存在i節(jié)點(diǎn),過濾掉i大于鏈表長度的情況(因?yàn)楣?jié)點(diǎn)是散列的,事先并不知道其長度) echo "不存在i節(jié)點(diǎn)" ; exit; }else{ /* 標(biāo)準(zhǔn)的插入語句(頭插法) */ $e->next = $p->next; $p->next = $e; return $list; } } /** * TODO:刪除鏈表的第i個節(jié)點(diǎn),并返回該節(jié)點(diǎn)的值 * @param $list object 待插入的鏈表 * @param $i int 節(jié)點(diǎn)序號 */ public function Delete($list,$i){ if($list == null || $i<=0){ echo "輸入?yún)?shù)不合法"; exit; } $p = $list->next; #設(shè)置p指向第一個節(jié)點(diǎn) $j=0; #計(jì)時器必須初始化 while($p && $j<$i ){ $p = $p->next; #保證節(jié)點(diǎn)在向后移動 ++$j; } /* 第i步 */ if($p == null){ #說明鏈表已經(jīng)結(jié)束,不存在i節(jié)點(diǎn),過濾掉i大于鏈表長度的情況,以為若i大于鏈表長度,則上面循環(huán)會跳出直接進(jìn)入判斷然后返回 echo "不存在i節(jié)點(diǎn)" ; exit; }else{ /* 標(biāo)準(zhǔn)的刪除語句 */ $q = $p->next; $p->next = $q->next; $e = $q->data; unset($q); return $e; } } /** * TODO:刪除整張鏈表 * @param $list object 待插入的鏈表 */ public function DeleteAll($list){ if($list == null ){ echo "輸入?yún)?shù)不合法"; exit; } $p = $list->next; #設(shè)置p指向第一個節(jié)點(diǎn) while($p != null ){ $q = $p->next; #保證節(jié)點(diǎn)在向后移動 unset($p); $p = $q; } } /** * Question1:輸出倒數(shù)第K個節(jié)點(diǎn) * @param $head object 鏈表 * @param $k int 序號 */ function FindKthToTail($head, $k){ /* 如果鏈表為空或者k不合法 返回null */ if($head == null || $k<=0){ return null; } /* 這里采用了復(fù)雜度為O(n)的算法,需要準(zhǔn)備兩個節(jié)點(diǎn) */ $behind = $head; #指向鏈表的第一個節(jié)點(diǎn) /* 算法思路:準(zhǔn)備兩個指針,假如第一個指針走到n-1(即鏈表末尾),第二個指針走到倒數(shù)k的位置,兩者之間相差(n-1)-(n-k) = k-1 */ for($i=0;$i<$k-1;$i++){ /* 讓第一個指針先走k-1個單位,如果不為空,則指針向后移動 */ /* 注意:這里有一個隱藏的條件,就是鏈表的長度有可能小于k,我們不不遍歷完整個鏈表是無法知道其長度的 */ if($head->next != null){ $head = $head->next; }else{ return ; } } /* 當(dāng)?shù)谝粋€指針走到k-1且還不為空,這時讓第二個指針開始走,當(dāng)?shù)谝粋€指針走到n-1的時候,第二個指針也走到了倒數(shù)第k的位置,即所求 */ while($head->next != null){ $head = $head->next; $behind = $behind->next; } return $behind; } /** * Question2:反轉(zhuǎn)鏈表 * @param $head object 鏈表 */ public function ReverseList($pHead) { /* 如果鏈表為空,返回null */ if($pHead == null){ return null; } $pre = $pHead; #前一節(jié)點(diǎn) ,這里是根節(jié)點(diǎn) $cur = $pre->next; #當(dāng)前節(jié)點(diǎn) 2 例:1->2->3 $next = null; #后一節(jié)點(diǎn) /* 鏈表存在且不為空 */ while(!$cur){ $next = $cur->next; #用一個變量暫時存儲后一節(jié)點(diǎn),因?yàn)橐坏┣懊娣崔D(zhuǎn),就斷鏈了 $cur->next = $pre; #將前一節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)的后一節(jié)點(diǎn),是為反轉(zhuǎn) #指針后移 $pre = $cur; $cur = $next; } return $pre; } } $object = new SingleLinkList(); $result = (new SingleLinkList)->headInsert(4); $pre = $object->ReverseList($result); //$behind = $object->FindKthToTail($result,1); // $e = $object->readIThNode($result,2); // echo $e; // $newNode = new Node(6,null); // $newList = $object->Insert($result,2,$newNode); // $e = $object->Delete($result,2); echo ""; // print_r($result); print_r($pre);
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/25965.html
摘要:一定要認(rèn)真看分析注釋題目要求題目描述輸入一個鏈表,從尾到頭打印鏈表每個節(jié)點(diǎn)的值。分析因?yàn)殒湵碇挥兄喇?dāng)前結(jié)點(diǎn)才能知道下一結(jié)點(diǎn),所以不可能直接從后往前打印。 一定要認(rèn)真看 分析 | 注釋 | 題目要求 Question 1 題目描述:輸入一個鏈表,從尾到頭打印鏈表每個節(jié)點(diǎn)的值。 分析:因?yàn)殒湵碇挥兄喇?dāng)前結(jié)點(diǎn)才能知道下一結(jié)點(diǎn),所以不可能直接從后往前打印。這種逆序的算法(策略)我們常用棧這...
摘要:本系列所有文章第一篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之棧與隊(duì)列第二篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之鏈表第三篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之集合第四篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之字典和散列表第五篇文章學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之二叉搜索樹簡單介紹鏈表鏈表一種常見的數(shù)據(jù)結(jié)構(gòu),可 本系列所有文章:第一篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之棧與隊(duì)列第二篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之鏈表第三篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之集合第四篇文章:學(xué)習(xí)數(shù)...
摘要:回來更新一波,最近刷劍指,才又發(fā)現(xiàn)樹真是一個大頭,二叉樹的題目和變化運(yùn)用好多啊二叉樹算法引子很多人說二叉樹沒什么卵用,我覺得是他的工資和公司讓他跨不過這個坎還有很多人學(xué)了一些樹的知識,發(fā)現(xiàn)也用不上,我想說的是,讀一本書體現(xiàn)不了這本書 回來更新一波,最近刷《劍指offer》,才又發(fā)現(xiàn)樹真是一個大頭,二叉樹的題目和變化運(yùn)用好多啊~ /** * PHP二叉樹算法 * Create...
摘要:劍指中鏈表相關(guān)題目俗話說光說不練假把式,既然學(xué)習(xí)了鏈表的基礎(chǔ)概念和基本操作那我們一定要找些題目鞏固下,下面來看劍指中的相關(guān)題目。題目分析合并兩個排序的鏈表,需要分別比較兩個鏈表的每個值,然后改變指針。 溫故知新 鏈表由一個一個的作為節(jié)點(diǎn)的對象構(gòu)成的,每一個節(jié)點(diǎn)都有指向下一個節(jié)點(diǎn)的指針,最后一個節(jié)點(diǎn)的指針域指向空。每個節(jié)點(diǎn)可以存儲任何數(shù)據(jù)類型。 根據(jù)類型可以分為單鏈表、雙鏈表、環(huán)形鏈表、...
摘要:回來更新一波,最近刷劍指,才又發(fā)現(xiàn)樹真是一個大頭,二叉樹的題目和變化運(yùn)用好多啊二叉樹算法引子很多人說二叉樹沒什么卵用,我覺得是他的工資和公司讓他跨不過這個坎還有很多人學(xué)了一些樹的知識,發(fā)現(xiàn)也用不上,我想說的是,讀一本書體現(xiàn)不了這本書 回來更新一波,最近刷《劍指offer》,才又發(fā)現(xiàn)樹真是一個大頭,二叉樹的題目和變化運(yùn)用好多啊~ /** * PHP二叉樹算法 * Create...
閱讀 3032·2020-01-08 12:17
閱讀 2000·2019-08-30 15:54
閱讀 1159·2019-08-30 15:52
閱讀 2043·2019-08-29 17:18
閱讀 1054·2019-08-29 15:34
閱讀 2468·2019-08-27 10:58
閱讀 1870·2019-08-26 12:24
閱讀 381·2019-08-23 18:23