線性表在採用不一樣的存儲結構時,它的描述方法是不同的,那麼它的基本操做實現方法也大相徑庭。下面來看線性表在順序存儲下,也就是順序表的每個基本操做的具體實現方法以及編寫方法。數組
仍是上一個例子,一羣朋友去吃火鍋。此時有一個女生過來了,她叫小紅。小紅是小綠的女友,固然想和小綠坐在一塊兒,可是小綠旁邊是沒有空位置的。因此小綠麻煩他旁邊的朋友小黃和小黑依次移動了一個位置。這樣就空出了一個位置,小紅就能夠過來坐下了。這樣就完成了一個相似順序表插入的過程。數據結構
知道了順序表插入的大體過程,來看它用程序語言是如何編寫的。首先畫出了一個順序表函數
其中數據元素是連續存放的。接着標出了存放該順序表數據元素的數組下標。注意一下,數組下標是從 0 開始的,而順序表的元素標號是從 1 開始的。接着用 C++ 寫出了該插入操做的函數體:學習
bool ListInsert(SqList &L, int i, ElemType e) { if(i<1 || i>L.length+1) return false; if(L.length >= MaxSize) return false; for(int j=L.length; j>=i; j--) L.data[j] = L.data[j-1]; L.data[i-1] = e; L.length++; return true; }
它的返回值類型是一個布爾類型,表示若是插入成功會返回一個 True ,插入失敗會返回一個 False。它有三個參數,分別是一個引用類型的順序表 L,這裏爲何用引用類型?由於在函數體內部進行操做,實際上是做用一個局部變量上的,不會真正做用到這個參數上,若是不用引用類型,是不能把插入操做真正做用到傳入的順序表上的。接着是一個整型變量 i,它表示的是插入的位置,要注意在採用插入操做時,每每是前插法,這是一個默認規定。還有一點要注意的就是,i 對應的是順序表的表號而非數組的下標。最後一個參數是所插入的數據元素 e。3d
首先第一個條件 i<1 || i>L.length+1
,順序表的元素標號是從 1 開始的,i 表示的是插入的位置,若是插入的位置是 0 或者更小,又或者比 L.length+1
還大,都是不合法的。第二個條件判斷的是插入的數組是否有足夠空間去插入,由於數組不能夠增長容量,一旦滿了就沒用新的空間去提供插入了。循環語句中申請了變量 j 初始化爲順序表的長度,j 進行減一操做,一直到 j=i
的時候停止循環。循環體中 L.data[j] = L.data[j-1]
的意思就是把每個數據元素向後移了一位,一直移動到 ai 移動到原先 ai+1 的位置。 執行完了全部的循環,空出了一個位置用於插入,L.data[i-1] = e
就是把要插入的元素放到該位置。注意,在 i 的位置,元素對應的下標是 i-1。最後將順序表的長度加一。code
再來看一下這個程序的時間複雜度,當循環次數最少時,它就是最好的時間複雜度,何時循環次數最少呢?發現當在順序表的尾部,也就是 L.length+1
的時候,這時候不用進行元素的移動,它的循環次數是 0,因此它的最好時間複雜度是 O(1) ,由於它的語句頻度是常數級別的。blog
接着來看平均時間複雜度,平均時間複雜度是在全部狀況等機率的狀況下,計算它的指望。這裏的等機率,必定是合法的狀況。因此 i 一共有 n+1 個合法位置,n 個數據元素,加上第 n 個數據元素以後的那個位置,均可以進行插入。因此每個插入等機率的狀況下,它的機率是:class
接着根據機率的知識,能夠用每個位置的機率乘以它循環的次數,它是從尾部一直循環到 i ,因此循環了 n-i+1
次,根據等差數列求和公式能夠計算:變量
計算結果與 n 同階無窮大,因此它的平均時間複雜度爲 O(n) 。List
最壞就是循環次數最多,即每個數據元素都要向後移動一位,也就是插入在第一個位置時是最壞的狀況,因此要循環 n 次,因此最壞狀況下的時間複雜度是 O(n) 。
仍是一羣小夥伴在等候區等待吃火鍋,這時小綠被他的女友叫回去一塊兒學習數據結構,那麼小綠要走了,小綠走了以後就空出了一個位置。在等候區中間是不能夠有空的位置的,因此說小黃和小黑兩我的會依次向前移一位。
這也就是刪除操做的大體過程。接着來看它的代碼實現。
bool ListDelete(SqList &L, int i, ElemType &e) { if(i<1 || i>L.length) return false; e = L.data[i-1] for(int j=i; j<L.length; j++) L.data[j-1] = L.data[j]; L.length--; return true; }
函數的返回值依舊是一個布爾類型。它有三個參數,分別是一個引用類型的順序表 L,一個整型變量 i 表示刪除的位置,一個引用類型的數據元素 e ,這裏使用引用類型也是由於在函數體內部進行操做,是做用在一個局部變量上的,不會真正做用到這個參數 e 上,因此說使用引用類型來將所刪除的這個數據元素真正的返回到函數外部。
第一個條件是判斷刪除的位置是否合法。接着 e = L.data[i-1]
是在保存要刪除的數據元素,將 i
位置的數據元素,對應下標 i-1
,賦值給 e
。而後循環從 i
開始,每次進行加一操做,一直循環到 L.length-1
爲止,也就是從 i
一直循環到 n-1
,將 ai 賦值給 ai+1 ,也就是將數組下標爲 i
的賦值給 i-1
的,這樣就將 ai 以後的全部數據元素都向前移了一位。接着將順序表的長度減一。
最好的時間複雜度是刪除最後一個元素,它的最好時間複雜度是 O(1) 。
全部合法的刪除位置有 n 個,由於有 n 個數據元素。因此每個合法位置的機率都是 1/n
,它的循環次數是從 i 循環到 L.length-1
,因此是 n-i
次,因此它的指望是 (n-1)/2
,它與 n 同階無窮大,因此它的平均時間複雜度爲 O(n) 。
刪除第一個數據元素循環的次數最多,此時須要循環 n-1 次,與 n 同階無窮大,所以最壞時間複雜度爲 O(n) 。
須要找到等候區的小綠,等候區是這樣依次坐下的。因而依次進行查找,從第一個位置開始,一直找到第三個位置,發現他是小綠。
這樣的查找過程,就與按值查找的函數十分類似。
int Locate(SqList &L, ElemType e) { int i; for(i=0; i<L.length; i++) if(L.data[i] == e) return i+1; return 0; }
這個函數的返回值是一個整型變量,它表示返回的是一個順序表的下標。兩個參數分別是查找的順序表以及查找的值。全部對輸入參數進行修改的操做,都使用引用類型。全部進行查找的操做都不會使用引用類型。
首先是一個整型變量 i ,它用來存放最終的輸出結果。接着是一個循環,變量 i 從下標 0,也就是第一個元素開始,每一次循環進行加一操做,一直循環到 L.length-1 ,也就是下標 n-1 的位置,一共執行了 n 次。循環體的內容是一個判斷語句,判斷此時數據元素是否爲要找的那個元素,若是相等返回當前順序表的下標,也就是 i+1。最後 return 0 表示循環結束了,尚未找到對應的這個值的位置,那麼就說明順序表當中是沒有該值的,此時就返回一個 return 0 表示查找失敗。
最好的時間複雜度依舊是循環的次數最少,也就是第一個數據元素就是要找的那個值,因此最好的時間複雜度爲 O(1) 。
一共有 n 個元素,查找機率是 1/n
,查找次數是 n-i
次,它的指望是 (n+1)/2
,它與 n 同階無窮大,因此它的平均時間複雜度爲 O(n) 。
最後一個元素被找到是最壞的狀況,循環了 n 次,所以最壞時間複雜度爲 O(n) 。