1. 程式人生 > >詳述線性表(單鏈表,雙鏈表,靜態連結串列和迴圈連結串列)

詳述線性表(單鏈表,雙鏈表,靜態連結串列和迴圈連結串列)

線性表:由零個或多個數據元素組成的有限序列。     關鍵點:
  1. 有限序列
  2. 第一個元素有且僅有一個前驅結點,最後一個與元素有且僅有一個後繼結點,中間元素有一個前驅結點和一個後繼結點
  3. 線性表可以有零個資料元素,稱作空表
線性表分為順序儲存結構和鏈式儲存結構 順序儲存結構:     用一段地址連續的儲存空間依次儲存線性表中的資料結構 物理關係上:         就是在記憶體中找個初始地址,然後通過佔位的方式,把一定的記憶體空間佔領,然後把相同資料型別的資料元素依次存放在這塊記憶體上。  屬性:
  1. 儲存空間的起始位置,陣列data,它的儲存位置就是線性表儲存空間的儲存位置
  2. 線性表的最大儲存容量:陣列的長度 MAXSIZE
  3. 線性表的當前長度:length
    注意: 陣列的長度與線性表的當前長度需要區分一下,陣列的長度是存放線性表的儲存空間的總長度,一般初始化後不變,而線性表的當前長度是線性表中元素的個數,是會變化的。     順序連結串列插入操作:
        思路:
  1. 如果插入位置不合理,丟擲異常
  2. 如果線性表長度大於等於陣列長度,則丟擲異常或動態擴容
  3. 從最後一個元素開始向前遍歷到第 i 個位置,分別將它們都向後移動一個位置
 注意:線性表從 1 開始     順序連結串列刪除操作:      思路:
  1. 如果刪除位置不合理,丟擲異常
  2. 取出刪除元素
  3. 從刪除元素位置開始遍歷到最後一個元素位置,分別將它們都向前移動一個位置
  4. 表長減一
  1. /*初始條件:順序線性表L已存在,1<=i<=ListLength(L)*/
  2. /*操作結果:刪除L的第i個數據元素,並用e返回其值,L的長度-1*/
  3. StatusListDelete(Sqlite*L,int i,ElemType*e)
  4. {
  5. int k;
  6. if(L -> length ==0)
  7. {
  8. return ERROR;
  9. }
  10. if(i <1|| i > L -> length)
  11. {
  12. return ERROR;
  13. }
  14. *e = L -> data(i -1);
  15. if(i < L
    -> length)
  16. {
  17. for(k = i; k < L -> length; k++)
  18. {
  19. L -> data(k -1)= L -> data(k);
  20. }
  21. }
  22. L -> length --;
  23. return OK;
  24. }
時間複雜度:         最好情況:插入和刪除操作剛好要求在最後一個位置操作,因為不需要移動任何位置,所以此時的時間複雜度為O(1);
        最壞情況:如果要插入和刪除的位置是第一個元素,那就意味著要移動所有的元素向後或者向前,所以這個時間複雜度為 O(n); 線性表順序儲存結構的優缺點:     線性表的順序儲存結構,在存、讀資料時,不管是哪個位置,時間複雜度都是 O(1),而在插入或刪除時,時間複雜度都是 O(n)。         它比較適合元素個數比較穩定,不經常插入和刪除元素,而更多的操作是存取資料的應用
優點:
  • 無須為表中元素之間的邏輯關係而增加額外的儲存空間
  • 可以快速地存取表中任意位置的元素
        缺點:
  • 插入和刪除操作需要移動大量元素
  • 當線性表長度變化比較大時,難以確定儲存空間的容量
  • 容易造成儲存空間的 ”碎片”
線性表的鏈式儲存結構:     出現鏈式儲存結構的出現,就是為了解決順序儲存結構的缺點——插入資料和刪除資料時需要移動大量元素。     為什麼插入和刪除元素時需要移動大量元素?
        原因在於相鄰兩元素的儲存位置也具有相鄰關係,它們在記憶體中的位置是緊挨著的,中間沒有間隙,無法快速的插入和刪除。
    特點:
  • 用一組任意的儲存單元儲存線性表的資料元素, 這組儲存單元可以存在記憶體中未被佔用的任意位置
  • 順序儲存結構每個資料元素只需要儲存一個位置就可以了,而鏈式儲存結構中,除了要儲存資料資訊外,還要儲存它的後繼元素的儲存地址(指標)
    單鏈表:
        對於線性表來說,總得有個頭有個尾,連結串列也是這樣。我們把連結串列中的第一個結點的儲存位置叫做頭指標,最後一個結點指為空。        頭指標和頭結點的異同?
        頭指標:
  • 頭指標是指連結串列指向第一個結點的指標,若連結串列有頭結點,則是指向頭結點的指標
  • 頭指標具有標識作用,所以常用頭指標冠以連結串列的名字(指標變數的名字)
  • 無論連結串列是否為空,頭指標均不為空
  • 頭指標是連結串列的必要元素
        頭結點:
  • 為了操作的統一和方便而設立的,放在第一個元素的結點之前,其資料域一般無意義(但也可以用來存放連結串列的長度)
  • 有了它頭結點,對在第一元素結點前插入結點和刪除第一結點的操作和其他結點的操作就統一了。
  • 頭結點不一定是連結串列的必要元素
    單鏈表的讀取
        思路:
  1. 宣告一個結點 p 指向連結串列第一個結點,初始化 j 從 1 開始
  2. 當 j < i 時,就遍歷連結串列,讓 p 的指標向後移動,不斷指向下一結點, j + 1
  3. 若到連結串列末尾 p 為空,則說明第 i 個元素不存在
  4. 查詢成功,返回結點 p 的資料
  1. /*初始條件:順序線性表L已存在,1<=i<=ListLength(L)*/
  2. /*操作結果:刪除L的第i個數據元素,並用e返回其值,L的長度-1*/
  3. StatusGetElem(LinkList*L,int i,ElemType*e)
  4. {
  5.     int k;
  6.    LinkList p;
  7.     p = L -> next;
  8.    j =1;
  9.    while(p && j <1)
  10.    {
  11.      p = p -> next;
  12.     ++j;
  13.    }
  14.     if(!p || j > i)
  15.     {
  16.         return ERROR;
  17.     }
  18.     *e = p -> data;
  19.     return OK;
  20. }
單鏈表的插入
        思路:
  1. 宣告一結點 p 指向連結串列頭結點,初始化 j 從 1 開始
  2. 當 j < i 時,就遍歷連結串列,讓 p 的指標向後移動,不斷指向下一結點, j ++
  3. 若到連結串列末尾 p 為空,則說明第 i 個元素不存在
  4. 否則查詢成功,在系統中生成一個空結點 s
  5. 將資料元素 e 賦值給 s -> data
  6. 單鏈表的兩條插入語句
  7. 返回成功
 注意:順序不能錯
  1. /*初始條件:順序線性表L已存在,1<=i<=ListLength(L)*/
  2. /*操作結果:刪除L的第i個數據元素,並用e返回其值,L的長度-1*/
  3. StatusGetElem(LinkList*L,int i,ElemType*e)
  4. {
  5. int k;
  6. LinkList p,s;
  7. p =*L;
  8. j =1;
  9. while(p && j <1)
  10. {
  11. p = p -> next;
  12. j++;
  13. }
  14. if(!p || j > i)
  15. {
  16. return ERROR;
  17. }
  18. s =(LinkList)malloc(sizeof(Node));
  19. s -> data = e;
  20. s -> next = p -> next;
  21. p -> next = s;
  22. return OK;
  23. }
    單鏈表的刪除
        思路:
  1. 宣告結點 p 指向連結串列第一個結點,初始化 j = 1
  2. 當 j < 1 時, 就遍歷連結串列, 讓 p 的指標向後移動,不斷指向下一節點, j++
  3. 若到連結串列末尾 p 為空,則說明第 i 個元素不存在
  4. 否則查詢成功,將欲刪除的結點 p -> next 賦值給 q
  5. 單鏈表刪除語句:p -> next = q -> next
  6. 將 q 結點中的資料賦值給 e,作為返回值
  7. 釋放 q 結點
  1. /*初始條件:順序線性表L已存在,1<=i<=ListLength(L)*/
  2. /*操作結果:刪除L的第i個數據元素,並用e返回其值,L的長度-1*/
  3. StatusGetElem(LinkList*L,int i,ElemType*e)
  4. {
  5. int k;
  6. LinkList p,q;
  7. p =*L;
  8. j =1;
  9. while(p && j <1)
  10. {
  11. p = p -> next;
  12. j++;
  13. }
  14. if(!p || j > i)
  15. {
  16. return ERROR;
  17. }
  18. q = p -> next;
  19. p -> next = q -> next;
  20. *e = q -> data;
  21. free(q);
  22. return OK;
  23. }
效率對比:
  • 在插入和刪除操作上,連結串列與順序儲存都由兩部分組