一文搞定常見的鍊錶問題

2021-10-24 15:00:53 字數 3396 閱讀 7640

作為線性表的兩種儲存方式 —— 鍊錶和陣列,這對相愛相殺的好**有著各自的優缺點。接下來,我們梳理一下這兩種方式。

陣列,所有元素都連續的儲存於一段記憶體中,且每個元素占用的記憶體大小相同。這使得陣列具備了通過下標快速訪問資料的能力。

但連續儲存的缺點也很明顯,增加容量,增刪元素的成本很高,時間複雜度均為 o(n)。

增加陣列容量需要先申請一塊新的記憶體,然後複製原有的元素。如果需要的話,可能還要刪除原先的記憶體。

刪除元素時需要移動被刪除元素之後的所有元素以保證所有元素是連續的。增加元素時需要移動指定位置及之後的所有元素,然後將新增元素插入到指定位置,如果容量不足的話還需要先進行擴容操作。

總結一下陣列的優缺點:

鍊錶,由若干個結點組成,每個結點包含資料域和指標域。結點結構如下圖所示:

一般來講,鍊錶中只會有乙個結點的指標域為空,該結點為尾結點,其他結點的指標域都會儲存乙個結點的記憶體位址。鍊錶中也只會有乙個結點的記憶體位址沒有儲存在其他結點的指標域,該結點稱為頭結點

鍊錶的儲存方式使得它可以高效的在指定位置插入與刪除,時間複雜度均為 o(1)。

在結點 p 之後增加乙個結點 q 總共分三步:

申請一段記憶體用以儲存 q (可以使用記憶體池避免頻繁申請和銷毀記憶體)。

將 p 的指標域資料複製到 q 的指標域。

更新 p 的指標域為 q 的位址。

刪除結點 p 之後的結點 q 總共分兩步:

將 q 的指標域複製到 p 的指標域。

釋放 q 結點的記憶體。

//定義乙個結點模板

templatestruct node

node(const t &d) : data(d), next(nullptr) {}

};//刪除 p 結點後面的元素

templatevoid remove(node*p)

auto tmp = p->next->next;

delete p->next;

p->next = tmp;

}//在 p 結點後面插入元素

templatevoid insert(node*p, const t &data)

//遍歷鍊錶

templatevoid walk(node*p, const v &vistor)

}int main() );

cout << sum << endl;

remove(p);

sum = 0;

walk(p, [&sum](const node*p) -> void );

cout << sum << endl;

return 0;

}無法高效獲取長度,無法根據偏移快速訪問元素,是鍊錶的兩個劣勢。然而面試的時候經常碰見諸如獲取倒數第k個元素,獲取中間位置的元素,判斷鍊錶是否存在環,判斷環的長度等和長度與位置有關的問題。這些問題都可以通過靈活運用雙指標來解決。

tips:雙指標並不是固定的公式,而是一種思維方式~

設有兩個指標 p 和 q,初始時均指向頭結點。首先,先讓 p 沿著 next 移動 k 次。此時,p 指向第 k+1個結點,q 指向頭節點,兩個指標的距離為 k 。然後,同時移動 p 和 q,直到 p 指向空,此時 q 即指向倒數第 k 個結點。可以參考下圖來理解:

設有兩個指標 fast 和 slow,初始時指向頭節點。每次移動時,fast向後走兩次,slow向後走一次,直到 fast 無法向後走兩次。這使得在每輪移動之後。fast 和 slow 的距離就會增加一。設煉表有 n 個元素,那麼最多移動 n/2 輪。當 n 為奇數時,slow 恰好指向中間結點,當 n 為偶數時,slow 恰好指向中間兩個結點的靠前乙個(可以考慮下如何使其指向後乙個結點呢?)。

下述**實現了 n 為偶數時慢指標指向靠後結點

class solution 

return p;

} };

如果將尾結點的 next 指標指向其他任意乙個結點,那麼鍊錶就存在了乙個環。

上一部分中,總結快慢指標的特性 —— 每輪移動之後兩者的距離會加一。下面會繼續用該特性解決環的問題。

當乙個鍊錶有環時,快慢指標都會陷入環中進行無限次移動,然後變成了追及問題。想象一下在操場跑步的場景,只要一直跑下去,快的總會追上慢的。當兩個指標都進入環後,每輪移動使得慢指標到快指標的距離增加一,同時快指標到慢指標的距離也減少一,只要一直移動下去,快指標總會追上慢指標。

根據上述表述得出,如果乙個鍊錶存在環,那麼快慢指標必然會相遇。實現**如下:

class solution 

if(fast == slow)

slow = slow->next;

}return nullptr;}};

方法是,快慢指標相遇後繼續移動,直到第二次相遇。兩次相遇間的移動次數即為環的長度。

一文搞定聯合索引

聯合索引 上文講解了索引的底層結構,但是留了乙個尾巴,就是沒有去講復合索引。今天來繼續梳理復合索引,所謂復合索引即是由多個字段組成的一條索引。例如下表 create table test id int 4 notnull auto increment a varchar 10 not null b ...

一文搞定babel轉換

code轉換為ast 遍歷ast樹 進行修改 還原為code targets支援哪些瀏覽器 babel polyfill是將整個es2015 環境引入到全域性中,會造成全域性汙染require core js modules set 改變了原型,所以可以在例項上使用方法 通過配置usebuiltin...

一文搞定開發學習環境

剛開始學寫 首先要搭建開發環境。新手需要在網上查閱教程,很多時候會遇到各種問題,甚至導致自己的學習進度卡住,學習熱情也因此而減少,這實在是個讓人煩的事情。我們可以簡單分析原因,並慢慢減少此類問題的發生。搭建開發環境經常出錯的原因 1.開發環境不匹配 我們在學習或者實際的開發中,有多種開發平台,比如w...