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("链表不为空。 "); 7 else 8 printf("链表为空. "); 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 ", 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