1,不帶頭結點的單鏈表操作中,除了InitList(),GetElem(),ListInsert(),ListDelete()操作與帶頭結點的單鏈表有差別外,其它的操作基本上一樣。
2,不帶頭結點單鏈表示意圖:
鏈表指針直接指向了首元節點,因此在首元節點前插入數據元素或者刪除首元節點元素都會改變頭指針的值。
3,不帶頭結點的單鏈表定義及操作集合,除了插入,刪除,清空操作需要傳遞頭指針的地址外,基本上一樣。頭文件defs.h
1 #ifndef _DEFS_H_ 2 #define _DEFS_H_ 3 4 #include<stdio.h> 5 #include<malloc.h> //malloc(),free() 6 #include<stdlib.h> //exit() 7 8 struct LNode 9 { 10 int data; 11 int * next; 12 }; 13 typedef struct LNode * linklist; 14 15 //操作集合,注意ClearList,ListInsert,ListDelete 16 void InitList(linklist *L); 17 void DestroyList(linklist *L); 18 void ClearList(linklist *L); //這里,清空和撤銷一樣 19 void ListEmpty(linklist L); 20 int ListLength(linklist L); 21 int GetElem(linklist L, int i, int *e); 22 int LocateElem(linklist L, int e); 23 int PriorElem(linklist L, int cur_e, int *pri_e); 24 int NextElem(linklist L, int cur_e, int *nex_e); 25 int ListInsert(linklist *L, int i, int e); //注意在首元結點前插入時改變頭指針 26 int ListDelete(linklist *L, int i, int *e); //刪除首元結點時改變頭指針 27 void TravelList(linklist L); 28 #endif //只要是能夠改變頭指針的值,均是傳遞頭指針的地址
4,InitList操作。其不需要分配結點,直接令頭指針為空

1 #include"defs.h" 2 3 void InitList(linklist *L) 4 { 5 (*L) = NULL; //*L即表示頭指針 6 }
5,DestroyList操作.其就是釋放所有結點。

1 #include"defs.h" 2 3 void DestroyList(linklist *L) 4 { 5 linklist p; //p為移動指針 6 while (*L) 7 { 8 p = (*L)->next; //釋放某一結點時,需保存其下一個結點的地址 9 free(*L); 10 *L = p; 11 } 12 }
6,ClearList操作。其意思和撤銷一樣,釋放所有結點.(帶頭結點的清空,保留了頭結點)

1 #include"defs.h" 2 3 void ClearList(linklist *L) 4 { 5 linklist p; 6 while (*L) 7 { 8 p = (*L)->next; 9 free(*L); 10 *L = p; 11 } 12 }
7,ListEmpty操作.判斷鏈表是否為空。

1 #include"defs.h" 2 3 void ListEmpty(linklist L) 4 { 5 if (L) //L不為空 6 printf("鏈表不為空。\n"); 7 else 8 printf("鏈表為空.\n"); 9 }
8,ListLength操作。求鏈表的長度,需要從第一個結點開始遍歷。

1 #include"defs.h" 2 3 int ListLength(linklist L) 4 { 5 int j = 0; //作為計數器 6 linklist p = L; 7 while (p) 8 { 9 ++j; 10 p = p->next; 11 } 12 return j; 13 }
9,GetElem操作。需要判斷元素位置的合法性。

1 #include"defs.h" 2 3 int GetElem(linklist L, int i, int *e) 4 { 5 int j = 1; //j記第一個結點開始 6 linklist p = L; 7 8 if (i<1) //位置不合法 9 exit(0); 10 while (p && j<i) //找到第i個結點 11 { 12 ++j; 13 p = p->next; 14 } 15 if (j==i && p) //判斷第i個位置元素是否存在,同時也解決了i = 1的情況 16 *e = p->data; 17 18 return 0; 19 }
10,LocateElem操作。需要從表一個結點遍歷。查找成功返回其位置值,失敗則返回-1

1 #include"defs.h" 2 3 int LocateElem(linklist L, int e) 4 { 5 linklist p = L; 6 int j = 0; 7 8 while (p) 9 { 10 ++j; 11 if (p->data == e) 12 return j; 13 p = p->next; //更新p 14 } 15 return -1; //查找失敗,返回-1 16 }
11,PriorElem操作。

1 #include"defs.h" 2 3 int PriorElem(linklist L, int cur_e, int *pri_e) 4 { 5 linklist p = L; 6 linklist q; 7 8 while (p) 9 { 10 q = p->next; //q指向p的后繼 11 if (q && q->data == cur_e) //q存在,且q的數據和當前值相等 12 { 13 *pri_e = p->data; //p即為q前驅 14 return 0; 15 } 16 p = q; //更新p 17 } 18 19 return 0; 20 }
12,NextElem操作。 求前驅與后繼的操作,基本一樣。兩個指針。

1 #include"defs.h" 2 3 int NextElem(linklist L, int cur_e, int *nex_e) 4 { 5 linklist p = L; 6 linklist q; 7 8 while (p) 9 { 10 q = p->next; //q指向p的后繼 11 if (q && p->data == cur_e) //q存在且p的數據與當前值相等 12 { 13 *nex_e = q->data; //q即為p的后繼 14 return 0; 15 } 16 p = q; 17 } 18 return 0; 19 }
13,ListInsert操作。

1 #include"defs.h" 2 3 int ListInsert(linklist *L, int i, int e) 4 { 5 int j = 1; //j從1開始計數 6 linklist p = *L; 7 linklist q, s; 8 9 if (i<1) //位置不合理 10 exit(0); 11 12 s = (linklist)malloc(sizeof(struct LNode)); 13 s->data = e; 14 15 if (i==1) 16 { 17 s->next = p; 18 *L = s; 19 } 20 else 21 { 22 while (p && j<i-1) //找到第i-1個結點 23 { 24 ++j; 25 p = p->next; 26 } 27 if (p) 28 { 29 q = p->next; //q指向第i個結點,q可以為空 30 s->next = q; 31 p->next = s; 32 } 33 } 34 return 0; 35 }
14,ListDelete操作。

1 #include"defs.h" 2 3 int ListDelete(linklist *L, int i, int *e) 4 { 5 int j = 1; 6 linklist p = *L; 7 linklist q; 8 9 if (*L == NULL) //鏈表為空 10 exit(0); 11 if (i==1) 12 { 13 q = p->next; //q指向p的后繼,保存后一個地址 14 free(*L); 15 *L = q; 16 } 17 else 18 { 19 while (p && j<i-1) //找到第i-1個位置 20 { 21 ++j; 22 p = p->next; 23 } 24 q = p->next; //q指向第i個位置 25 if (!q || i<1) //第i個位置不存在 26 exit(0); 27 p->next = q->next; //p指向第i+1個位置 28 free(q); //釋放第i個結點 29 } 30 31 }
15,TravelList操作。

1 #include"defs.h" 2 3 void TravelList(linklist L) 4 { 5 int j = 0; 6 linklist p = L; 7 while (p) 8 { 9 ++j; 10 printf("第%d個結點值為: %d\n", j, p->data); 11 p = p->next; //更新p 12 } 13 }
16,main.c測試代碼里,初始插入時應該從第一個位置開始插入。(初始時為空表)
17,makefile文件。

1 object : main.o InitList.o DestroyList.o ClearList.o ListEmpty.o \ 2 ListLength.o GetElem.o LocateElem.o PriorElem.o NextElem.o \ 3 ListInsert.o ListDelete.o TravelList.o 4 5 test : $(object) 6 gcc -g -Wall -o test $(object) 7 8 $(object) : defs.h 9 10 .PHONY : clean 11 clean : 12 rm -f *.o