順序表的插入刪除算法移動元素次數分析


設:L.elem[0..maxleng-1] 中有 legth 個元素,

在 L.elem[i-1] 之前插入 新元素 e ,1<=i<=length

例:i = 3,e = 6,length = 6

 

如上圖,我們需要在第三個元素,也就是 "8" 之前插入 “6”,

因此需要將 “8”,“20“,”30”,“35” 這些元素統統后移一格

如下圖:

--------------------------------------------------分---------------界---------------線------------------------------------------------------------

 

 

 也就是將,從第 i-1 個元素開始,統統向后移動一位,然后將元素 “x” 插入 第 "i-1" 個位置,即下圖:

 

移動元素下標范圍:i - 1 ~ n - 1 或 i - 1 ~ L.length - 1

 

元素移動方向為:是從 最后一個元素 an 開始,一直到 ai 處,依次向后移動一個位置,而非從 第 ai 開始。

基於此思想,進行一個動態表插入與靜態表插入的對比:

算法①:靜態分配線性表空間,用指針指向被操作的線性表(下圖)

算法思想:
① 判斷插入的位置是否合理即:if ( i<1 || i>L.length+1 ) return ERROR; 

i 這里指的是第幾個元素,而非下標。

因此,i<1這里即插入位置不合理。(我們無法在 第0個 元素前插入,因為它不存在)

L.length + 1 :我們為了插入元素順利,因此讓線性表占用存儲空間為元素數量+1,

體現在這里就是 L.length + 1,i 超出這個值,則無法插入(沒位置了,添加不進去)

② 判斷表長是否達到分配空間的最大值,

if (L.length>=maxleng) return OVERFLOW

如果 線性表長度 大於等於 最大長度,這里是從線性表長度的角度表達規則。

③ 從線性表中的最后一個位置到插入位置的所有元素,依次往后移動一個元素的位置,這樣給待插入元素留出一個空位置

 

 

即:L.elem[j+1] = L.elem[j]; //將原位置元素賦值給新位置

④ 線性表長度變量 + 1,L.length ++;

⑤ return ok,返回結果,表示插入成功。

 

關於 for 循環部分:

1. 從最后一個元素開始,依次向后移動一位

2. j = L.length - 1 // L.length 即線性表長度,L.length - 1 即線性表中 最后一位元素 的 下標

3. j >= i-1 為 for 循環的條件,當下標變成 i - 1 時停止 for 循環。在滿足 j>=i-1 條件的情況下,才會進行for 循環,不滿足這個條件,就停止 for 循環,同時 “;”是在 L.elem[j+1] = L.elem[j] 這個代碼后,因此 for 循環在運行過程中,它的運行范圍就止步於此。

4. L.elem[j+1] = L.elem[j] 將下標為 j 的元素,賦值到下標為 j+1 的位置。

--------------------------------------------------分---------------界---------------線------------------------------------------------------------

動態 分配線性表空間,用 引用參數 表示被操作的線性表

偽代碼部分(如下圖)

 

 

如果插入元素使得表長超過原來分配的空間大小時,這時候可以使用:

 

 

newbase = (ElemType *) realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));

尋找更大片的連續地址空間,但極端情況下可能發生擴容失敗。

如果找到新的更大片的連續地址空間后,我們要將線性表的基地址改成一個新地址。

代碼講解:

L.length:當前數據元素的個數(即線性表的長度)

L.listsize:當前分配的存儲容量

ElemType *newbase:定義一個Elemtype類型的指針變量

關於 realloc :

語法 指針名=(數據類型*)realloc(要改變內存大小的指針名,新的大小)
代碼 newbase = (ElemType *) realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType))
代碼含義 之前定義了一個結構體,名為ElemType, 現在使用realloc()函數重新分配一塊內存。這個內存的大小為 (L.lestsize+LISTINCREMENT) ElemType結構體。
Elemtype * 聲明下面的變量是指針,指向Elemtype類型
LISTINCREMENT 線性表或者鏈表存儲空間增量
備注 新的大小可大可小(如果新的大小大於原內存大小,則新分配部分不會被初始化;如果新的大小小於原內存大小,可能會導致數據丟失)
功能 先判斷當前的指針是否有足夠的連續空間,如果有,擴大mem_address指向的地址,並且將mem_address返回,如果空間不夠,先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝到新分配的內存區域,而后釋放原來mem_address所指內存區域(注意:原來指針是自動釋放,不需要使用free),同時返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。
返回值 如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。
注意 當內存不再使用時,應使用free()函數將內存塊釋放。

 

 

 

 

 

 

 

 

 

 

 

L.elem = newbase:新基地址,

L.listsize += LISTINCREMENT:增加存儲容量

for 循環代碼塊:從最后一個開始,到第 i 個元素,挨個往后挪

L.elem[i - 1] = e:將元素 "e" 賦值給被空出來的 原第 i-1 個元素 的存儲位置

L.length++:線性表長度加一

--------------------------------------------------分---------------界---------------線------------------------------------------------------------

插入操作  移動元素次數  的分析

 

 

總之,在一個線性表中,往里面插入一個元素的時候,它移動元素的長度的數學期望值,是等於線性表長度的一半。

--------------------------------------------------分---------------界---------------線------------------------------------------------------------

在線性表中刪除元素,同樣也存在移動元素的過程,只是這個移動方向和插入元素時的移動方向是相反的。

a1 a2 ... ai-1 ai ai+1 ...   an // //

 

 

比如對上邊這個線性表中的元素 “ai” 進行刪除時,需要把 ai+1 一直到 an ,依次向原 ai 位置移動一格。變成如下:

a1 a2 ... ai-1 ai+1 ...   an  // //  

 

 

刪除代碼如下:

 

 代碼中算法基本思想:

① 判斷刪除元素的下標是否存在。關於此處用 ->

-> 是指針操作符 如果 L 是一個結構實例的指針,要用 -> 訪問結構里的變量,而不能用點。
. 是結構操作符 如果L 是一個結構的實例而非指針,只能用點而不能用 -> 

 

 

 

② 用一個 for 循環來移動元素,移動元素下標范圍為 i 到 length - 1

③ 修改表長為原表長減一

--------------------------------------------------分---------------界---------------線------------------------------------------------------------

刪除操作及移動元素次數的分析:

刪除元素的位置只有 n 中情形。

 

 --------------------------------------------------分---------------界---------------線------------------------------------------------------------

一個思考題:順序存儲結構的線性表插入一個元素算法的時間復雜度是平方數量及的嗎?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM