前面我们所讲的线性表的顺序存储结构,它是有优缺点,最大的缺点是插入与删除时需移动大量的元素,这显然需要耗费许多时间。这时,我们就引入线性表的链式存储结构,它的特点是:用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据可以存在内存中未被占用的任意位置上,即当线性表进行插入与删除时就不需要移动大量的元素了,节约了时间。
链式结构中,除了需要存储数据元素的信息外,还要存储它的后继元素的存储地址。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。这两部分信息组成数据元素的存储映像,称为“结点”;n个结点链接成一个链表,我们称之为“单链表”。注意:链表的第一个结点的存储位置叫做头指针,整个链表的存取是从头指针开始的;同时我们规定链表的最后一个结点指针为“空”(通常用“NULL”表示)。有时,为了方便对链表进行操作,在单链表的第一个结点前附设一个结点,称为“头结点”,头结点的数据域可以不用存储任何信息,指针域存储指向第一个结点的指针。对于一个单链表来说,进行一系列插入、删除、初始化、置空等操作是非常重要的。下面,我们来看看单链表是如何进行插入与删除等操作,具体操作源代码如下所示:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define OK 1 5 #define ERROR 0 6 #define TRUE 1 7 #define FALSE 0 8 9 #define MAXSIZE 100 /* 存储空间初始分配量 */ 10 11 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */ 12 typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */ 13 14 15 Status visit(ElemType c) 16 { 17 printf("%d ",c); 18 return OK; 19 } 20 21 typedef struct Node 22 { 23 ElemType data; 24 struct Node *next; 25 }Node; 26 typedef struct Node *LinkList; /* 定义LinkList */ 27 28 /* 初始化顺序线性表 */ 29 Status InitList(LinkList *L) 30 { 31 *L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */ 32 if(!(*L)) /* 存储分配失败 */ 33 return ERROR; 34 (*L)->next=NULL; /* 指针域为空 */ 35 36 return OK; 37 } 38 39 /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */ 40 Status ClearList(LinkList *L) 41 { 42 LinkList p,q; 43 p=(*L)->next; /* p指向第一个结点 */ 44 while(p) /* 没到表尾 */ 45 { 46 q=p->next; 47 free(p); 48 p=q; 49 } 50 (*L)->next=NULL; /* 头结点指针域为空 */ 51 return OK; 52 } 53 54 /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */ 55 int ListLength(LinkList L) 56 { 57 int i=0; 58 LinkList p=L->next; /* p指向第一个结点 */ 59 while(p) 60 { 61 i++; 62 p=p->next; 63 } 64 return i; 65 } 66 67 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */ 68 /* 操作结果:用e返回L中第i个数据元素的值 */ 69 Status GetElem(LinkList L,int i,ElemType *e) 70 { 71 int j; 72 LinkList p; /* 声明一结点p */ 73 p = L->next; /* 让p指向链表L的第一个结点 */ 74 j = 1; /* j为计数器 */ 75 while (p && j<i) /* p不为空或者计数器j还没有等于i时,循环继续 */ 76 { 77 p = p->next; /* 让p指向下一个结点 */ 78 ++j; 79 } 80 if ( !p || j>i ) 81 return ERROR; /* 第i个元素不存在 */ 82 *e = p->data; /* 取第i个元素的数据 */ 83 return OK; 84 } 85 86 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */ 87 /* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */ 88 Status ListInsert(LinkList *L,int i,ElemType e) 89 { 90 int j; 91 LinkList p,s; 92 p = *L; 93 j = 1; 94 while (p && j < i) /* 寻找第i个结点 */ 95 { 96 p = p->next; 97 ++j; 98 } 99 if (!p || j > i) 100 return ERROR; /* 第i个元素不存在 */ 101 s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */ 102 s->data = e; 103 s->next = p->next; /* 将p的后继结点赋值给s的后继 */ 104 p->next = s; /* 将s赋值给p的后继 */ 105 return OK; 106 } 107 108 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */ 109 /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */ 110 Status ListDelete(LinkList *L,int i,ElemType *e) 111 { 112 int j; 113 LinkList p,q; 114 p = *L; 115 j = 1; 116 while (p->next && j < i) /* 遍历寻找第i个元素 */ 117 { 118 p = p->next; 119 ++j; 120 } 121 if (!(p->next) || j > i) 122 return ERROR; /* 第i个元素不存在 */ 123 q = p->next; 124 p->next = q->next; /* 将q的后继赋值给p的后继 */ 125 *e = q->data; /* 将q结点中的数据给e */ 126 free(q); /* 让系统回收此结点,释放内存 */ 127 return OK; 128 } 129 130 /* 初始条件:顺序线性表L已存在 */ 131 /* 操作结果:依次对L的每个数据元素输出 */ 132 Status ListTraverse(LinkList L) 133 { 134 LinkList p=L->next; 135 while(p) 136 { 137 visit(p->data); 138 p=p->next; 139 } 140 printf(" "); 141 return OK; 142 } 143 144 int main() 145 { 146 LinkList L; 147 ElemType e; 148 Status i; 149 int j,k; 150 151 i=InitList(&L); 152 printf("1.初始化L后:ListLength(L)=%d ",ListLength(L)); 153 154 for(j=1;j<=6;j++) 155 i=ListInsert(&L,1,j); 156 printf("2.在L的表头依次插入1~6后:L.data="); 157 ListTraverse(L); 158 printf("ListLength(L)=%d ",ListLength(L)); 159 160 i=ClearList(&L); 161 printf("3.清空L后:ListLength(L)=%d ",ListLength(L)); 162 163 for(j=1;j<=10;j++) 164 ListInsert(&L,j,j); 165 printf("4.在L的表尾依次插入1~10后:L.data="); 166 ListTraverse(L); 167 168 ListInsert(&L,1,0); 169 printf("5.在L的表头插入0后:L.data="); 170 ListTraverse(L); 171 printf("ListLength(L)=%d ",ListLength(L)); 172 173 j=5; 174 ListDelete(&L,j,&e); 175 printf("7.删除第%d个的元素值为:%d ",j,e); 176 printf("依次输出L的元素:"); 177 ListTraverse(L); 178 179 ListInsert(&L,5,4); 180 printf("8.插入第5个元素值后,依次输出L的值:L.data="); 181 ListTraverse(L); 182 183 return 0; 184 }