1、單鏈表
單鏈表的定義
線性表的鏈式存儲又稱單鏈表,它是指任意一組存儲單元來存儲線性表中的數據元素。
data(數據域) | next(指針域) |
---|
typedef struct LNode{
ElemType data; //數據域
struct LNode *next;//指針域
}LNode, *LinkList;
通常用頭指針來標識一個單鏈表,如單鏈表L,頭指針爲NULL時爲空表。單鏈表在第一個結點前附加一個結點,稱爲頭結點。頭結點的數據域可以不設任何值,也可以存儲表長等相關信息。
頭結點和頭指針的區分:
不管帶不帶頭結點,頭指針始終指向鏈表的第一個結點。
引入頭結點可以帶來兩個優點:
1)由於開始結點的位置被存放在頭結點的指針域,所以在鏈表的第一個位置上的操作和在表中的其他位置的操作是一致的,無須特殊處理。
2)無論鏈表是否爲空,頭指針都指向頭結點的非空指針,因此空表和非空表也得到了統一。
單鏈表上基本操作的實現
1)採用頭插法建立單鏈表
LinkList List_HeadInsert(LinkList &L){
LNode *s;
int x;
L=(LinkList)malloc(sizeof(LNode));//創建頭結點
L->next=NULL;//初始空鏈表
scanf("%d",&x);
while(x!=9999){//輸入9999標識結束
s=(LNode*)malloc(sizeof(LNode));//創建新結點
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
return L;
}
每個結點插入時間爲O(1),則時間複雜度爲O(n)
2)採用尾插法建立單鏈表
該方法將新結點插入到當前鏈表的表尾,爲此必須增加一個尾指針r。
LinkList List_TailInsert(LinkList &L){
int x;
L=(LinkList)malloc(sizeof(LNode));
LNode *s, *r=L;//r爲表尾指針
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;//r指向新的表尾結點
scanf("%d",&x);
}
r->next=NULL:
return L;
}
時間複雜度爲O(n),和頭插法相同
3)按序號查找結點值
LNode *GetElem(LinkList L,int i){
int j=1;
LNode *p=L->next;//頭結點指針賦值給p
if(i==0) return L;
if(i<1) return NULL;
while(p&&j<i){//從第一個結點開始找,找第i個
p=p->next;
j++;
}
return p;
}
時間複雜度爲O(n)
4)按值查找表結點
LNode *LocateElem(LinkList L,ElemType e){
LNode *p=L->next;
while(p!=NULL&&p->data!=e){
p=p->next;
}
return p;
}
時間複雜度O(n)
5)插入結點操作
p=GetElem(L,i-1);
s-next=p->next;//s爲新結點
p->next=s;
三個語句的順序不可以亂
6)刪除結點操作
p=GetElem(L,i-1);//找到被刪除結點的前驅結點
q=p->next;
p->next=q->next;
free(q);
時間複雜度O(n)
2、雙鏈表
雙鏈表的定義
單鏈表結點只有一個指向其後的指針,使得單鏈表只能從頭結點依次順序的向後遍歷。爲克服單鏈表缺點,引入雙鏈表,雙鏈表中有兩個指針prior和next,分別指向前驅和後繼結點。
*prior | data | *next |
---|
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
雙鏈表的操作實現
1)雙鏈表的插入操作
s->next=p->next;
p->next->prior=s;
s->prior=p;
p->next=s;
2)雙鏈表的刪除操作
p->next=q->next;
q->next->prior=p;
free(q);
3、循環雙鏈表
循環雙鏈表的定義
循環雙鏈表L頭結點的prior指向表尾結點,表尾結點的next指向L。當循環雙鏈表爲空時,其頭結點的prior和next都等於L。
4、靜態鏈表
靜態鏈表的定義
靜態鏈表藉助數組來描述線性表的鏈式存儲,結點也有data和next
#define MaxSize 50
typedef struct{
ElemType data;
int next;//存儲下一個元素的數組下標
}SLinkList[MaxSize];
靜態鏈表以next等於-1作爲結束
5、順序表和鏈表的比較
1)存儲方式
順序表可以順序存儲也可以隨機存儲,鏈表只能從表頭到表尾存取元素。
2)邏輯結構和物理結構
採用順序存儲時,邏輯上相鄰的元素,對應物理存儲位置也相鄰。而採用鏈式存儲時,邏輯上上相鄰的元素,物理存儲位置不一定相鄰。
3)查找、插入和刪除操作
對於按值查找,順序表無序時,兩者的時間複雜度均爲O(n)。順序表有序時,可採用折半查找,時間複雜度爲O(logn)。
對於按序號查找,順序表支持隨機訪問,時間複雜度僅爲O(1),而鏈表的時間複雜度爲O(n)。