1. 程式人生 > >資料結構學習筆記(一)

資料結構學習筆記(一)

一.陣列

      陣列用一塊連續的記憶體空間,來儲存形同型別的一組資料,最大的特點就是支援隨機訪問,但插入,刪除操作也因此變得比較低效(為了保持記憶體資料的連續性),平均情況時間複雜度為O(n)。在平時的業務開發中,我們可以直接使用程式語言提供的容器類,但是,如果是特別底層的開發,直接使用陣列可能會更合適。
ArrayList:
      1.Java ArrayList無法儲存基本型別,比如int,long,需要封裝為Integer,Long類,而Autoboxing,Unboxing則有一定的效能消耗。如果特別關注效能,或者希望使用基本型別,就可以選用陣列。
      2.如果資料大小事先已知,並且對資料的操作非常簡單,用不到ArrayList提供的大部分方法,也可以直接使用陣列。
      3.ArrayList可以實現動態擴容

二.連結串列

      雙向連結串列可以支援O(1)的時間複雜度找到前驅節點,正是這樣的特性使得雙向連結串列在某些情況下進行插入、刪除等操作時比單鏈表高效。
例如:
      要刪除某個節點,已經找到了要刪除的節點。但是刪除節點需要知道前驅節點,對於這種情況單鏈表需要從頭再遍歷一次連結串列,找到要刪除節點的前驅節點。而雙向連結串列就不存在這種問題,直接可以獲取前驅節點。

三、連結串列與陣列的區別

      1.陣列簡單易用,在實現上利用的是連續的記憶體空間,可以藉助CPU的快取機制,預讀陣列中的資料,所以訪問效率更高。而連結串列在記憶體中並不是連續儲存,所以對CPU快取

不友好,沒辦法預讀。
      2.陣列的缺點是大小固定,一經宣告就要佔用整塊連續記憶體空間。而連結串列本身沒有大小的限制,天然地支援擴容。
      3.如果對記憶體的使用非常苛刻,那陣列就更加適合。因為連結串列每個節點都要佔用空間去儲存下一個節點的指標,所以記憶體消耗會翻倍。而且,對連結串列進行頻繁的插入、刪除操作,會導致頻繁的記憶體申請和釋放 ,容易造成記憶體碎片,有可能導致頻繁的GC。

四、陣列與CPU快取機制

      CPU在從記憶體中讀取資料的時候,會把讀取到的資料載入到CPU快取中。CPU每次從記憶體中讀取資料並不是讀取那個特定要訪問的地址,而是讀取一個數據塊並儲存到CPU快取中。然後下次需要訪問資料的時候會先從緩衝中查詢,如果找不到就在記憶體中取。這樣就實現了比記憶體訪問更快的機制,也就是CPU緩衝存在的意義:為了彌補記憶體訪問速度過慢與CPU執行速度快之間的差異而引入。對於陣列來說,儲存空間是連續的,所以在載入某個下標的時候可以把以後的幾個元素也載入到CPU緩衝中,這樣執行速度會快於儲存空間不連續的連結串列儲存。

五、基於連結串列實現LRU緩衝

      維護一個有序單鏈表,越靠近連結串列尾部的結點是越早之前訪問的。當有一個新的資料被訪問時,我們從連結串列頭開始順序遍歷連結串列:
      如果此資料之前已經被快取在連結串列中了,我們遍歷得到這個資料對應的結點,並將其從原來的位置刪除,然後再插入到連結串列的頭部。
      如果此資料沒有在快取連結串列中,又可以分為兩種情況:

  • 如果此時快取未滿,則將此結點直接插入到連結串列的頭部
  • 如果此時快取已滿,則連結串列尾節點結點刪除,將新的資料結點插入連結串列的頭部。