1. 判斷單鏈表是否有環
這是很多公司入門級的面試筆試題。單鏈表由於每個結點只有乙個next指標指向下乙個結點,不存在其他指標,所以一旦進入環裡,就再也出不去了。類似於下圖(像乙個烤盤)
那麼怎麼樣判斷單鏈表是否有環呢?方法很簡單,把環看作操場,兩位選手在操場上賽跑,乙個速度快,乙個速度慢,如果他們一直跑,快的選手肯定會在第一次超過慢的選手之後再次追上慢的選手,與他相遇;若現在沒有環,那麼快的選手將始終跑在慢的選手前面,不可能有第二次相遇。所以我們判斷乙個鍊錶是否有環的方法就是基於這個思想:
在鍊錶頭部設兩個指標,乙個每次向後移動兩個位置(快指標),另乙個每次向後移動乙個位置(慢指標)。這相當於在起點設定了兩位跑步選手,跑的快的選手的速度是慢的選手的兩倍。接下來兩個指標在遍歷鍊錶過程中,如果快指標到達鍊錶尾還沒有和慢指標相遇,說明鍊錶無環,反之說明有環。
2. 獲得環的入口點
書上說的公式挺複雜的,我們這裡只要考慮兩個指標第一次相遇的情況就好了。第一次相遇的條件是:快指標在環內比慢指標多走了一圈。如下圖所示,兩個指標從起點o出發,在環中的b點相遇,現在我們的目標是如何根據b點找到a點這個結點。注意:結點在環中的前進方向是順時針,即a→b→a.
毫無疑問,兩個指標第一次在b點相遇時:
慢指標走過的路程是:
s_slow = |oa| +|ab| = x + y.
快指標走過的路程是:
s_fast = |oa| + |ab| + |ba| + |ab| = x + y + z + y.
又因為快指標的速度是慢指標的兩倍,所以在相同時間內快指標走過的路程是慢指標的兩倍,所以
s_fast = 2 * s_slow
即 2(x + y) = x + y + z + y.
求得 z = x.
所以說明
|ba| = |oa|.
所以在兩個指標相遇後,將慢指標移到o點起始位置,即煉表頭指標位置,快指標仍然在b點。然後它們一起向前移動,每次移動乙個位置,由於|ba| = |oa|, 所以他們最終肯定會在a點相遇,a點這個相遇點就是環的入口點。
具體實現**如下:
#include#includeusing namespace std;
typedef struct lnodelnode;
void createlistr(lnode *&head,int arr,int n);//尾插法建立帶頭結點的單向鍊錶
void showlist(lnode *head);
lnode * search(lnode *head,int x);
lnode *hascircal(lnode *head);//判斷是否有環,無返回nullptr,有則返回快慢結點相遇位址
lnode *findenter(lnode *head);//尋找環入口點位址
int main();
createlistr(head,arr,sizeof(arr)/sizeof(arr[0]));
showlist(head);
//構造乙個單向有環鏈表
lnode *p = search(head,112);//設定環入口點
lnode *end = search(head,126);
if(p != nullptr && end != nullptr)
end->next = p;
if(hascircal(head) != nullptr)
puts("有環");
else
puts("無環");
lnode *node = findenter(head);
if(node != nullptr)
printf("環入口結點為:%d\n",node->data);
else
puts("無環");
return 0;
}lnode *findenter(lnode *head)
return slow;
}lnode *hascircal(lnode *head)
return nullptr;
}lnode * search(lnode *head,int x)
p = p->next; }
return nullptr;
} void createlistr(lnode *&head,int arr,int n)//尾插法
} void showlist(lnode *head)
puts("");
}
面試題 判斷單鏈表是否有環
題目 如何在o 1 空間複雜度的條件下判斷單鏈表是否有環。思路 採用快慢指標,如果有環,兩指標一定會相遇。圖示 圖1 初始化情況,建立兩個指標都指向head節點。圖2 p指標為慢指標,每次只走一步 q指標為快指標,每次走兩步。圖3 p q繼續往後走。圖4 p q繼續往後走。圖5 p q繼續往後走。圖...
判斷單鏈表中是否有環
define crt secure no deprecate include include include include define ok 1 define error 0 define true 1 define false 0 typedef int status 函式結果狀態 如ok。t...
判斷單鏈表中是否有環
單鏈表中的迴圈鍊錶尾結點不一定指向頭結點,也可以指向任意中間結點。此時若想判斷單鏈表中是否有環,就不能只是簡單的根據尾結點的next是不是頭結點來判斷,在此我提供三種方法 方法一 建立兩個指標p和q,其中p用來遍歷指標,每次只走一步,並記錄從根節點出發所走的步數,而q則是每次從根節點出發,到達p此時...