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