演算法2 鍊錶,陣列,和選擇排序

2021-08-19 03:31:40 字數 3200 閱讀 8007

計算機的記憶體就像是我們平時存放東西的儲物櫃一樣,我們把揹包之類的物品放入櫃子裡,每個櫃子有乙個專屬的編號,我們記住這個編號,然後根據編號就可以找到櫃子拿回屬於我們的物體。

在計算機裡,就有很多這種櫃子,叫記憶體單元,每個櫃子的編號就是位址。那麼如何將資料存放到相應的位址內呢,有兩種基本方式,鍊錶和陣列,接下來我們分別介紹他們並比較其優缺點。

假如我們有乙個四乘四的格仔,即16個小格仔,相當於計算機的記憶體,從左到右,從上到小分別編號0-15。每個格仔代表乙個位址。此時,我有乙個包含四個數的陣列a[4],我們想把它放到這16個格仔當中,如果16格仔全部為空,我可以放到任意的位置上,比如0-3或者4-7,這個編號就代表陣列所存放的位址。但是這四個數必須是相鄰的,不能有跳躍。這就是陣列儲存在計算機記憶體的方式。

但是,如果這16個格仔不全為空,編號為3,7,11,15的格仔裡本身存有資料,我們不能占用,那我們還可以將陣列a[4]存入這16個格仔中嗎?答案是不能,因為我們發現已經沒有相鄰的4個格仔了,連在一起的格仔最多只有3個,那這時我們要怎麼儲存資料呢,這就引出了鍊錶。

鍊錶也是資料儲存在計算機記憶體裡的一種方式,不同於陣列的是,當我們儲存乙個數的時候,我們還會記下下乙個數所在的位址。這有什麼好處呢,回到上面的例子,現在編號3,7,11,15的格仔已經被占用了,假設我們將前三個數儲存在0-2編號的格仔裡,儲存第乙個數時會包括第二個數的位址,第二個數會包括第三個數的位址,儲存放在編號2的格仔裡的第三個數還包括第四個數的位址。假設我們將第四個數存在編號4的格仔裡(因為編號3的格仔已經被占用),當我們讀到第三個數時,由於有了第四個數的位址,我們可以直接跳到編號4的格仔中讀取裡面的數字。而陣列由於不儲存下乙個資料所在的位址,所以我們必須將他們相鄰排列,前乙個位址加一就是後乙個數的位址所在。

現在我們知道了陣列和鍊錶的工作原理,那麼誰更好呢。當然世界上沒有絕對的優勢與劣勢,鍊錶和陣列也有各自擅長的情形,接下來我們考慮幾個操作,讀取,插入,刪除。

讀取 (陣列 優於 鍊錶)

假設我們想從陣列裡讀取第四個元素,由於陣列是相鄰排列,我們只需要將頭元素的位址加4就可以直接訪問到第四個元素,只是簡單的加法運算即可得到,相當於直接查表,所以執行時間是o(1)。

假設我們想從煉表裡讀取第四個元素,鍊錶不一定是相鄰排列,我們必須從第乙個查到第二個的位址,從第二個再查第三個,從第三個再查第四個,無論我們查第幾個元素,都要遍歷一遍這個元素前面的所有元素才可以找到我們想要的,所以執行時間是o(n)。

插入(鍊錶 優於 陣列)

假設我們想在包含四個資料的陣列再插入乙個資料,則陣列的大小發生了變化,首先我們需要確保加了乙個資料之後,記憶體中還有五個相鄰的格仔,其次,如果我們把新資料插在頭乙個,那麼所有後面的數都要相應往後挪一位,每乙個資料本身的位址都發生了變化,所以執行時間是o(n)。

假設我們想在包含四個資料的煉表裡插入乙個新資料,假如插在第二位,我們可以將新資料放入到任意乙個空的格仔裡,然後讓第乙個數記下這個新資料格仔的位址,這樣第乙個數之後我們就查詢到第二個數,也就是新資料,我們再讓新資料儲存原本第二個數的位址,這樣從新數可以查到舊的第二位數,這樣新資料就被加進了原本的第一位數和第二位數之間。那麼後面的資料呢?我們完全不需要動,對吧。所以執行時間是o(1)。

刪除(鍊錶 優於 陣列)

刪除的操作和插入的操作很相像。對於陣列而言,刪除乙個元素也是改變了陣列本身的大小,如果刪除第乙個元素,後面所有元素都要向前挪一位,所有元素位址都要變,執行時間是o(n)。

而對於鍊錶,一樣原理,鍊錶有乙個叫頭結點(head)的東西,顧名思義它是開始,它儲存著第乙個數的位址,如果我們要刪除第乙個元素的時候,只需要將頭結點裡的位址改為原本第二個數的位址,這樣從頭節點我們就直接跳到了原來的第二個數上,原本的第乙個數自然而然就被刪除掉了,而後面的數字則全部不需要動,所以執行時間是o(1)。

我想下面這幅圖可以更好的幫助理解關於鍊錶的操作。綠色箭頭代表指向下乙個元素的位址,紫色箭頭是跨過e直接指向了a的位址,也就是相當於刪除元素e的操作了。鍊錶操作比較難理解,我會在之後放入更為詳細的講解。

在演算法1裡我們講到了二分查詢,每次先找中間的然後比較,但這必須是有序的數列,如果是無序的數列呢?這裡我們將一種比較簡單直觀,效率可能較低,但很基本的排序方法,選擇排序。

假如我們有5個學生,他們是數學成績如下,很明顯這是無序的,我們想要按照成績從高到低的順序進行排列,要如何做呢?

最簡單的方法就是,先從頭到尾看一遍找到最高的挑出來,然後再從頭到尾查一遍挑出第二高,...,然後第三高,第四高,直至最後。很簡單對吧,這就是選擇排序。很簡單易懂,當然花費時間也很高,來讓我們算算它的執行時間。

假設有n個同學需要排序,第一次需要檢視n個同學找到最高,第二次只需要檢視n-1個同學,然後n-2個同學,直至查到最後一名,所以總時間t = n + (n-1) +(n-2) + ... + 1 = n(n+1)/2 = (n^2+n)/2 ,而時間複雜度我們一般忽略常數項取最高次的多項,所以這裡選擇排序的執行時間是o(n^2).

def findsmallest(lst):

smallest = lst[0]

smallest_index = 0

for i in range(len(lst)):

print('com',lst[i],smallest)

if lst[i] < smallest:

smallest = lst[i]

smallest_index = i

return smallest_index

def selectionsort(lst):

new_list =

while len(lst) > 0:

smallest_index = findsmallest(lst)

print(lst)

return new_list

mylst = [1,2,3,4,1,2]

mynew_lst =

mynew_lst = selectionsort(mylst)

print(mynew_lst)

reference: 理解**於《演算法**》

演算法基礎 陣列 鍊錶 選擇排序

1 說說記憶體的工作原理?1 記憶體 就像很多抽屜的集合體,每個抽屜都有位址,fe0ffeeb是乙個記憶體單元的位址 2 將資料儲存到記憶體時,請求計算機提供空間,計算機給你乙個儲存位址。需要儲存多項資料時,有兩種儲存方式 陣列 鍊錶。2 說說陣列的原理?4個人去看電影,以陣列的形式將4個人儲存在座...

演算法初探 陣列 鍊錶與選擇排序

前端也要懂演算法,閱 演算法 有所得。1.記憶體的原理 相信我們經常會聽到 堆 棧 之類的字眼,那麼計算機的記憶體是什麼呢?當我們去游泳時,我們需要將東西存在保險櫃裡,可能東西比較多,乙個放不下,這時候就需要申請2個保險櫃,再將東西放在櫃子裡,手裡拿著開櫃的鑰匙。計算機的記憶體分配亦是如此,當我們需...

演算法講解 選擇排序 陣列鍊錶

陣列 使用陣列儲存item意味著所有item在記憶體中都是相連的。在陣列中儲存新的item可能很麻煩,because if 沒有了新空間,就得移動到記憶體的其他地方,因此新增新元素會很慢。陣列刪除元素也很麻煩,刪除元素後,必須將後面的元素前移。結決辦法1 預留空間。缺點 1 額外請求的位置可能用不上...