設計乙個演算法完成以下功能:判斷乙個鍊錶是否有環,如果有,找出環的入口點並返回,否則返回null。
設定快慢兩個指標分別為fast和slow,初始時都指向煉表頭 head。slow每次走一步,即slow=slow->next; fast每次走兩步,即fast=fast->next->next。由於fast 比 slow走得快,如果有環,fast一定會先進入環,而slow後進入環。當兩個指標都進入環後,經過若干次操作後兩個指標定能在環上相遇。這樣就可以判斷乙個鍊錶是否有環。
如下圖所示,當slow剛進入環時,fast早已進入環。因為fast每次比 slow多走一步且fast與slow的距離小於環的長度,所以fast與slow相遇時,slow所走的距離不超過環的長度。
如下圖所示,設頭結點到環的入口點的距離為a,環的入口點沿著環的方向到相遇點的距離為x,環長為r,相遇時fast繞過了n圈。
則有2(a+x)=a+nr+x,即 a=nr-x。顯然從頭結點到環的入口點的距離等於n倍的環長減去環的入口點到相遇點的距離。因此可設定兩個指標,乙個指向 head,乙個指向相遇點,兩個指標同步移動(均為一次走一步),相遇點即為環的入口點。
lnode*
findloopstart
(lnode *head)
if(slow==
null
||fast-
>next==
null
)return
null
;//沒有環,返回null
lnode *p1=head,
*p2=slow;
//分別指向開始點、相遇點
while
(p1!=p2)
return p1;
//返回入口點
}
首先這題的解法非常巧妙了的運用的快慢指標,如果有環的話進行追逐最後相遇。
但是王道這道題給出的**是有問題的,我們編寫如下**進行測試
#include
using
namespace std;
struct lnode
;lnode*
findloopstart
(lnode *head)
if(slow==
null
||fast-
>next==
null
)return
null
;//沒有環,返回null
lnode *p1=head,
*p2=slow;
//分別指向開始點、相遇點
while
(p1!=p2)
return p1;
//返回入口點
}int
main()
r->next=
null;
cout<<
findloopstart
(head)
<
return0;
}
鍊錶中有兩個結點,沒有環,輸出null
鍊錶中有三個結點,沒有環,應該輸出null,但卻死迴圈了
為什麼呢,我們每步輸出slow和fast的位址看一下
第一次slow走一步到0xa11490(第乙個元素結點),fast走兩步到0xa11930(第二個元素結點)
第二次slow走到0xa11930(第二個元素結點),fast應該走到第四個元素結點,但是鍊錶總共只有三個元素,所以fast走到了0(null),我們在看一下迴圈的條件
slow!=null&&fast->next!=null
,首先第乙個slow!=nul
成立,第二個fast->next!=null
這裡就有問題了,因為此時fast已經是空指標,所以執行fast->next
這條語句會產生空指標錯誤。
那麼我們下面對程式進行修改
lnode*
findloopstart
(lnode *head)
if(slow==
null
||fast==
null
||fast-
>next==
null
)return
null
;//沒有環,返回null
lnode *p1=head,
*p2=slow;
//分別指向開始點、相遇點
while
(p1!=p2)
return p1;
//返回入口點
}
我們在條件中加入了fast!=null
,然後運用邏輯運算子的短路性質,巧妙避免了空指標錯誤。 王道資料結構課後習題 P018
3.長度為l的順序表,編寫乙個時間複雜度為o n 空間複雜度為o 1 的演算法,該演算法刪除線性表中所有值為x的元素。一看就是典型的雙指標問題,於是我寫 如下 for i 0,j i 1 jif a j x else if a i x a i a j 這部分 是有問題的,如果出現在第一位的話就無法解...
王道資料結構課後習題 P37
3 設l為帶頭節點的單鏈表,編寫演算法實現從尾到頭反向輸出每個節點的值。我想到的是reverse一下 笑哭 想想這個就有點殺雞用牛刀的感覺 看了題解說是可以用遞迴 臥槽瞬間orz class solution 利用reverse將整個鍊錶倒置 void reverseoutput listnode ...
王道資料結構課後題 P121
7 判斷乙個二叉樹是否為完全 二叉樹。一開始是想著利用遞迴,判斷有左孩子而無右孩子的節點的個數,並且要求左孩子為葉子節點。判斷的條件很複雜,最後發現這種方法實際上是有問題的。如果同時碰到兩個節點同時為有左葉子節點而右子樹為空,這種情況按照判斷應當返回false 但是這種方法並不能正確返回 1 2 3...