資料結構是我們軟體開發中最基礎的部分了,它體現著我們程式設計的內功。大多數人在正兒八經學習資料結構的時候估計是在大學計算機課上,而在實際專案開發中,反而感覺到用得不多。
其實也不是真的用得少,只不過我們在使用的時候被很多高階語言和框架元件封裝好了,真正需要自己去實現的地方比較少而已。但別人封裝好了不代表我們就可以不關注了,資料結構作為程式設計師的內功心法,是非常值得我們多花時間去研究的,我這就翻開書複習複習:
本文就先從大家最經常使用的「 陣列 」和「 鍊錶 」聊起。不過在聊陣列和鍊錶之前,咱們先看一下資料的邏輯結構分類。通俗的講,資料的邏輯結構主要分為兩種:
知道了分類,下面我們來詳細看一下「 陣列 」和「 鍊錶 」的原理。
一、「 陣列 」是什麼?
陣列是乙個有限的、型別相同的資料的集合,在記憶體中是一段連續的記憶體區域。
如下圖:
陣列的下標是從0開始的,上圖陣列中有6個元素,對應著下標依次是0、1、2、3、4、5,同時,陣列裡面存的資料的型別必須是一致的,比如上圖中存的都是數字型別。陣列中的全部元素是「連續」的儲存在一塊記憶體空間中的,如上圖右邊部分,元素與元素之間是不會有別的儲存隔離的。另外,也是因為陣列需要連續的記憶體空間,所以陣列在定義的時候就需要提前指定固定大小,不能改變。
所以整體而言,陣列的訪問效率高,插入與刪除效率低。不過想改善陣列的插入與刪除效率也是有辦法的,來來來,下面的「 鍊錶 」了解一下。
二、「 鍊錶 」是什麼?
鍊錶是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過鍊錶中的指標鏈結次序實現的,一般用於插入與刪除較為頻繁的場景。
上圖是「單鏈表」示例,鍊錶並不需要陣列那樣的連續空間,它只需要乙個個零散的記憶體空間即可,因此對記憶體空間的要求也比陣列低。
鍊錶的每乙個節點通過「指標」鏈結起來,每乙個節點有2部分組成,一部分是資料(上圖中的data),另一部分是後繼指標(用來儲存後乙個節點的位址),在這條鏈中,最開始的節點稱為head,最末尾節點的指標指向null。
「 鍊錶 」也分為好幾種,上圖是最簡單的一種,它的每乙個節點只有乙個指標(後繼指標)指向後面乙個節點,這個鍊錶稱為:單向鍊錶,除此之外還有 雙向鍊錶、迴圈鍊錶 等。
雙向鍊錶:
雙向鍊錶與單向鍊錶的區別是前者是2個方向都有指標,後者只有1個方向的指標。雙向鍊錶的每乙個節點都有2個指標,乙個指向前節點,乙個指向後節點。雙向鍊錶在操作的時候比單向鍊錶的效率要高很多,但是由於多乙個指標空間,所以占用記憶體也會多一點。
迴圈鍊錶:
其實迴圈鍊錶就是一種特殊的單向鍊錶,只不過在單向鍊錶的基礎上,將尾節點的指標指向了head節點,使之首尾相連。
既然插入與刪除元素只需要改動指標,無需移動資料,那麼鍊錶的時間插入刪除的時間複雜度為o(1)不過這裡指的是找到節點之後純粹的插入或刪除動作所需的時間複雜度。
如果當前還未定位到指定的節點,只是拿到鍊錶的head,這個時候要去刪除此煉表中某個固定內容的節點,則需要先查找到那個節點,這個查詢的動作又是乙個遍歷動作了,這個遍歷查詢的時間複雜度卻是o(n),兩者加起來總的時間複雜度其實是o(n)的。
其實就算是已經定位到了某個要刪除的節點了,刪除邏輯也不簡單。以「刪除上圖的e節點」為例,假如當前鍊錶指標已經定位到了e節點,刪除的時候,需要將這個e節點的前面乙個節點h的後繼指標改為指向a節點,那麼e節點就會自動脫落了,但是當前鍊錶指標是定位在e節點上,如何去改變h節點的後續指標呢,對於「單向鍊錶」而言,這個時候需要從頭遍歷一遍整個鍊錶,找到h節點去修改其後繼指標的內容,所以時間複雜度是o(n),但如果當前是「雙向鍊錶」,則不需要遍歷,直接通過前繼指標即可找到h節點,時間複雜度是o(1),這裡就是「雙向鍊錶」相當於「單向鍊錶」的優勢所在。
三、「 陣列和鍊錶 」的演算法實戰?
通過上面的介紹我們可以看到「 陣列 」和「 鍊錶 」各有優勢,並且時間複雜度在不同的操作情況下也不相同,不能簡單一句o(1)或o(n)。所以下面我們找了個常用的演算法題來練習練習。
演算法題:反轉乙個單鏈表
輸入: 1->2->3->4->5->null
輸出: 5->4->3->2->1->null
/*** definition for singly-linked list.
* public class listnode
* }*/
class solution
//完成,時間複雜度為o(n)
return pre;}}
以上,就是對「 陣列與鍊錶 」的一些思考。
碼字不易啊,喜歡的話不妨**朋友吧。
演算法一看就懂之 堆疊
一 堆疊 是什麼?堆疊 stack 是一種先進後出的 操作受限的線性表,也可以直接稱為棧。可以把棧想象成乙個桶一樣,往這個桶裡面一層一層的放東西,先放進去的在裡面,後放進去的東西依次在外面。但取東西的時候就是先取靠近外面的,再依次一層層取裡面的。這就是 後進先出 last in first out ...
一看就懂的SwitchHosts
switchhosts 是乙個管理 切換多個 hosts 方案的工具。它是乙個免費開源軟體。日常開發工作中,我們可能經常需要切換各種 hosts 繫結,比如在本地開發時可能需要乙個開發環境的 hosts 繫結方案,發布到測試環境後又有乙個測試環境的 hosts 繫結方案,然後可能還有乙個預發布環境,...
一看就懂TCP 連線
我們先來看乙個定義。這樣理解比較抽象。我們換個角度。它的本質還是傳輸控制。如果讓我們自己設計這個傳輸,我們會怎麼想呢。tcp 協議它會先建立連線。三次握手目的是保證雙方都有傳送和接收的能力 首要原因是為了防止舊的重複連線初始化造成混亂。同步雙方初始序列號客戶端和服務端都處於 closed 狀態。先是...