文字描述:
为了表示前后两个数据元素的逻辑关系,对于每个数据元素,除了存储其本身的信息之外(数据域),还需存储一个指示其直接后继的信息(即直接后继的存储位置,指针域)。
示意图:
算法分析:
在单链表中插入和删除元素时,主要是改变指针的值,其时间复杂度为1。而顺序存储的话,其时间复杂度为n。
在单链表中求长度时不如顺序存储结构,其时间复杂度为n; 而顺序存储是1。故可以在链表头结点中设置一个长度值,在插入数据元素时加1,在删除数据元素时减1。
在单链表中查找指定数据元素时,其时间复杂度和顺序存草时一样,乱序情况下为n。
代码实现(动态单链表):
1 // 2 // Created by lady on 19-1-26. 3 // 4 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 9 //线性表的动态单链表存储结构 10 typedef struct ElemType{ 11 char data[10]; 12 }ElemType; 13 typedef struct LNode{ 14 ElemType e; 15 struct LNode *next; 16 }LNode, *LinkList; 17 18 /* 19 * 倒序法输入n个元素的值,建立带表头结点的单链表线性表L 20 */ 21 static int CreateList_L(LinkList *L, int n, char name[]) 22 { 23 printf("以倒插入法创建单链表存储结构的线性表%s:\n", name); 24 //先建立一个带头结点的单链表 25 if((*L=(LinkList)malloc(sizeof(LNode))) == NULL){ 26 return -1; 27 } 28 (*L)->next = NULL; 29 int i = 0; 30 LinkList p = NULL; 31 for(i=n; i>0; --i){ 32 //生成新的结点 33 p = (LinkList)malloc(sizeof(LNode)); 34 //输入元素值 35 printf("输入第%d个元素:", i); 36 scanf("%s[^\\n]", p->e.data); 37 //插入到表头 38 p->next = (*L)->next; 39 (*L)->next = p; 40 } 41 return 0; 42 } 43 44 /*依次对L的每个数据元素调用函数fun。一旦fun失败,则操作失败*/ 45 static int ListTraverse_L(LinkList L, int (*fun)(ElemType,int), char info[]) 46 { 47 printf("%s", info); 48 //跳过头结点 49 LNode *p = L->next; 50 int i = 1; 51 while(p){ 52 if(fun(p->e, i++)){ 53 printf("Err:when traverse(e,%d) wrong!\n",i); 54 } 55 p = p->next; 56 } 57 printf("\n"); 58 } 59 60 /* 61 * L为带头结点的单链表的头指针 62 * 当第i个元素存在是,其值赋给e并返回0,否则返回-1 63 */ 64 static int GetElem_L(LinkList L, int i, ElemType *e) 65 { 66 //初始化,p指向第一个结点 67 LNode *p = L->next; 68 //j为计数器 69 int j = 1; 70 while(p && j<i){ 71 //顺指针向后查找,知道p指向第i个元素或者p为空 72 p = p->next; 73 j+=1; 74 } 75 if(!p || j>i){ 76 //第i个元素不存在 77 return -1; 78 } 79 //取第i个元素 80 *e = p->e; 81 return 0; 82 } 83 84 /* 85 * 在带头结点的单链表线性表L中第i个位置之前插入元素e 86 */ 87 static int ListInsert_L(LinkList *L, int i, ElemType e) 88 { 89 LNode *p = (LNode *)(*L); 90 int j = 0; 91 while(p && j<i-1){ 92 //寻找第i-1个结点 93 p = p->next; 94 ++j; 95 } 96 //i小于1或者大于表长+1 97 if(!p || j>i) 98 return -1; 99 //生成新的结点 100 LinkList s = (LinkList)malloc(sizeof(LNode)); 101 s->e = e; 102 //将新结点插入到链表L中 103 s->next = p->next; 104 p->next = s; 105 return 0; 106 } 107 108 /* 109 * 在带头结点的单链线性表L中,删除第i个元素,并有e返回其值 110 */ 111 static int ListDelete_L(LinkList *L, int i, ElemType *e) 112 { 113 LNode *p = (LNode *)(*L); 114 LNode *q = NULL; 115 int j = 0; 116 while(p->next && (j<i-1)){ 117 //寻找第i个结点,并令p指向其前趋 118 p = p->next; 119 ++j; 120 } 121 if(!(p->next) || (j>i-1)){ 122 //删除位置不合理 123 return -1; 124 } 125 //删除该结点 126 q = p->next; 127 p->next = q->next; 128 *e = q->e; 129 //释放该结点的占用空间 130 free(q); 131 return 0; 132 } 133 134 /* 135 * 输入元素e的数据和位置 136 */ 137 static int printE(ElemType e, int location) 138 { 139 printf("%3d=%-10s", location, e.data); 140 return 0; 141 } 142 143 /* 144 * 已知单链线性表La和Lb的元素按值非递减排列 145 * 归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列 146 */ 147 static void MergeList_L(LinkList La, LinkList Lb, LinkList *Lc) 148 { 149 LNode *pa = La->next; 150 LNode *pb = Lb->next; 151 LNode *pc = NULL; 152 LNode *p; 153 //用La的头结点作为Lc的头结点 154 pc = (LNode*)La; 155 *Lc = La; 156 157 while(pa && pb){ 158 if(atoi(pa->e.data) <= atoi(pb->e.data)){ 159 //需要将当前的pa结点插入到pc结点 160 if(pc->next == pa){ 161 //pc结点正好在pa链表 162 pc = pc->next;//移动pc结点到下一个结点 163 pa = pa->next;//移动pa结点到下一个结点 164 }else{ 165 //需要将pa结点插入到pc结点后,插入后pc、pa结点要后移动 166 p = pa; 167 pa = pa->next; 168 p->next = pc->next; 169 pc->next = p; 170 pc = pc->next; 171 } 172 }else{ 173 if(pc->next == pb){ 174 pc = pc->next; 175 pb = pb->next; 176 } else{ 177 p = pb; 178 pb = pb->next; 179 p->next = pc->next; 180 pc->next = p; 181 pc = pc->next; 182 } 183 } 184 } 185 //插入剩余段 186 pc->next = pa?pa:pb; 187 //释放Lb的头结点 188 free(Lb); 189 } 190 191 /* 192 * 释放链表L 193 */ 194 static int DestoryList_L(LinkList *L) 195 { 196 if(L == NULL){ 197 return -1; 198 } 199 if(*L == NULL){ 200 return -1; 201 } 202 LNode *p, *q; 203 p = (LNode*)(*L); 204 while(p){ 205 q = p; 206 free(q); 207 p = p->next; 208 } 209 *L = NULL; 210 return 0; 211 } 212 213 int main(int argc, char *argv[]) 214 { 215 216 ElemType e; 217 int location = 0; 218 219 LinkList L; 220 CreateList_L(&L, 4, "L"); 221 ListTraverse_L(L, printE, "L:"); 222 223 printf("insert a data and print, please input (location, data):"); 224 scanf("%d,%s[^\\n]", &location, e.data); 225 ListInsert_L(&L, location, e); 226 ListTraverse_L(L, printE, "L:"); 227 printf("\n"); 228 229 printf("delete a data through location and print, please input (location):"); 230 scanf("%d[^\\n]", &location); 231 ListDelete_L(&L, location, &e); 232 printf("location %d, data %s is deleted from List\n", location, e.data); 233 ListTraverse_L(L, printE, "init:"); 234 printf("\n"); 235 236 printf("locate/find a data through location, please input (location):"); 237 scanf("%d[^\\n]", &location); 238 GetElem_L(L, location, &e); 239 printf("the data of what location is %d, is %s\n", location, e.data); 240 printf("\n"); 241 242 printf("Merge LA and LB to LC!\n"); 243 LinkList La, Lb, Lc; 244 //create La 245 CreateList_L(&La, 4, "La"); 246 ListTraverse_L(La, printE, "La:"); 247 //create Lb 248 CreateList_L(&Lb, 7, "Lb"); 249 ListTraverse_L(Lb, printE, "Lb:"); 250 //merge La and Lb to Lc 251 MergeList_L(La, Lb, &Lc); 252 ListTraverse_L(Lc, printE, "Lc:"); 253 254 DestoryList_L(&L); 255 DestoryList_L(&La); 256 DestoryList_L(&Lb); 257 }
代码运行(动态单链表):
/home/lady/CLionProjects/untitled/cmake-build-debug/untitled 以倒插入法创建单链表存储结构的线性表L: 输入第4个元素:ZHAO 输入第3个元素:QIAN 输入第2个元素:SUN 输入第1个元素:LI L: 1=LI 2=SUN 3=QIAN 4=ZHAO insert a data and print, please input (location, data):2,ZHOU L: 1=LI 2=ZHOU 3=SUN 4=QIAN 5=ZHAO delete a data through location and print, please input (location):3 location 3, data SUN is deleted from List init: 1=LI 2=ZHOU 3=QIAN 4=ZHAO locate/find a data through location, please input (location):3 the data of what location is 3, is QIAN Merge LA and LB to LC! 以倒插入法创建单链表存储结构的线性表La: 输入第4个元素:11 输入第3个元素:8 输入第2个元素:5 输入第1个元素:3 La: 1=3 2=5 3=8 4=11 以倒插入法创建单链表存储结构的线性表Lb: 输入第7个元素:20 输入第6个元素:15 输入第5个元素:11 输入第4个元素:9 输入第3个元素:8 输入第2个元素:6 输入第1个元素:2 Lb: 1=2 2=6 3=8 4=9 5=11 6=15 7=20 Lc: 1=2 2=3 3=5 4=6 5=8 6=8 7=9 8=11 9=11 10=15 11=20 Process finished with exit code 0
代码实现(静态单链表):
1 // 2 // Created by lady on 19-1-27. 3 // 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 //---------------线性表的静态单链表存储结构----------- 10 #define MAXSIZE 12 //链表的最大长度 11 typedef struct ElemType{ 12 char data[10]; 13 }ElemType; 14 typedef struct{ 15 ElemType e; 16 int cur; 17 }component,SLinkList[MAXSIZE]; 18 19 /* 20 * 依次打印静态链表space中的数据 21 */ 22 static void Debug_Print(SLinkList space, char note[]) 23 { 24 printf("%s\n", note); 25 int i = 0; 26 for(i=0; i<MAXSIZE; i++){ 27 printf("\tindex %-5d[data:%-5s,cur:%-2d]\n", i, space[i].e.data, space[i].cur); 28 } 29 } 30 31 /* 32 * 将一维数组space中各分量链成一个备用链表,space[0].cur为头指针, “0”表示空指针。 33 */ 34 static void InitSpace_SL(SLinkList space) 35 { 36 int i = 0; 37 for(i=0; i<MAXSIZE-1; ++i){ 38 memset(space[i].e.data, 0, sizeof(space[i].e.data)); 39 space[i].cur = i+1; 40 } 41 memset(space[MAXSIZE-1].e.data, 0, sizeof(space[MAXSIZE-1].e.data)); 42 space[MAXSIZE-1].cur = 0; 43 return ; 44 } 45 46 /* 47 * 如果备用空间链表非空,则返回分配的结点下标,否则返回0 48 */ 49 static int Malloc_SL(SLinkList space) 50 { 51 int i = 0; 52 i = space[0].cur; 53 if(space[0].cur) 54 space[0].cur = space[i].cur; 55 return i; 56 } 57 58 /* 59 * 将下标为k的空闲结点回收到备用链表。 60 */ 61 static int Free_SL(SLinkList space, int k) 62 { 63 space[k].cur = space[0].cur; 64 space[0].cur = k; 65 return 0; 66 } 67 68 /* 69 * 依次输入集合A和B的元素,在一维数组space中建立表示集合 (A-B)U(B-A)的静态链表,S为其头指针。 70 * 假设备用空间够大,space[0].cur为备用空间的头指针 71 */ 72 static void difference(SLinkList space, int *S) 73 { 74 printf("用静态链表算集合(A-B)U(B-A):\n"); 75 InitSpace_SL(space); //将space整个初始化成备用空间 76 (*S) = Malloc_SL(space);//生成S的头结点 77 int r = *S;//r始终指向静态链表S的最后一个元素。 78 int m, n; 79 int i, j; 80 char str[128] = {0}; 81 printf("step1\t:依次输入A和B集合的元素个数(m,n):"); 82 scanf("%d,%d[^\\n]", &m, &n); 83 printf("step2.1\t:依次输入A中的元素到集合S:\n"); 84 for(j=1; j<=m; ++j){ 85 i = Malloc_SL(space); 86 printf("\t输入A中第%d/%d个元素:", j, m); 87 scanf("%s[^\\n]", space[i].e.data); 88 //插入到表尾巴 89 space[r].cur = i; 90 r = i; 91 } 92 space[r].cur = 0; 93 Debug_Print(space, "step2.2\t:创建集合A后的集合S值"); 94 95 printf("step3\t:依次输入B中的元素,同时查找S表,如果已经存在则从S中删除之,否则加入到S!\n"); 96 ElemType b; 97 int p; 98 int k; 99 for(j=1; j<=n; ++j){ 100 memset(b.data, 0, sizeof(b.data)); 101 printf("\t输入B中第%d/%d个元素:", j, n); 102 scanf("%s[^\\n]", b.data); 103 p = (*S); 104 k = space[p].cur; //k指向集合A中第一个结点 105 while(k!=space[r].cur && strncmp(space[k].e.data, b.data, sizeof(b.data))){ 106 //在当前表中查找 107 p = k; 108 k = space[k].cur; 109 } 110 if(k == space[r].cur){ 111 //当前表中不存在该元素, 插入在r所值结点后,且r的位置不变。 112 i = Malloc_SL(space); 113 space[i].e = b; 114 space[i].cur = space[r].cur; 115 space[r].cur = i; 116 snprintf(str, sizeof(str), "step3.1\t:元素%s在S中不存在,插入之!",b.data); 117 Debug_Print(space, str); 118 }else{ 119 //该元素已在表中,则删除之 120 space[p].cur = space[k].cur; 121 Free_SL(space, k); 122 if(r == k){ 123 //如果删除的是r所指结点,则需修改尾指针。 124 r = p; 125 } 126 snprintf(str, sizeof(str), "step3.1\t:元素%s在S中存在,删除之!",b.data); 127 Debug_Print(space, str); 128 } 129 } 130 } 131 132 int main(int argc, char *argv[]) 133 { 134 SLinkList space; 135 int s; 136 //求(A-B)U(B-A) 137 difference(space, &s); 138 return 0; 139 }
代码运行(静态单链表):
/home/lady/CLionProjects/untitled/cmake-build-debug/untitled 用静态链表算集合(A-B)U(B-A): step1 :依次输入A和B集合的元素个数(m,n):6,4 step2.1 :依次输入A中的元素到集合S: 输入A中第1/6个元素:c 输入A中第2/6个元素:b 输入A中第3/6个元素:e 输入A中第4/6个元素:g 输入A中第5/6个元素:f 输入A中第6/6个元素:d step2.2 :创建集合A后的集合S值 index 0 [data: ,cur:8 ] index 1 [data: ,cur:2 ] index 2 [data:c ,cur:3 ] index 3 [data:b ,cur:4 ] index 4 [data:e ,cur:5 ] index 5 [data:g ,cur:6 ] index 6 [data:f ,cur:7 ] index 7 [data:d ,cur:0 ] index 8 [data: ,cur:9 ] index 9 [data: ,cur:10] index 10 [data: ,cur:11] index 11 [data: ,cur:0 ] step3 :依次输入B中的元素,同时查找S表,如果已经存在则从S中删除之,否则加入到S! 输入B中第1/4个元素:a step3.1 :元素a在S中不存在,插入之! index 0 [data: ,cur:9 ] index 1 [data: ,cur:2 ] index 2 [data:c ,cur:3 ] index 3 [data:b ,cur:4 ] index 4 [data:e ,cur:5 ] index 5 [data:g ,cur:6 ] index 6 [data:f ,cur:7 ] index 7 [data:d ,cur:8 ] index 8 [data:a ,cur:0 ] index 9 [data: ,cur:10] index 10 [data: ,cur:11] index 11 [data: ,cur:0 ] 输入B中第2/4个元素:b step3.1 :元素b在S中存在,删除之! index 0 [data: ,cur:3 ] index 1 [data: ,cur:2 ] index 2 [data:c ,cur:4 ] index 3 [data:b ,cur:9 ] index 4 [data:e ,cur:5 ] index 5 [data:g ,cur:6 ] index 6 [data:f ,cur:7 ] index 7 [data:d ,cur:8 ] index 8 [data:a ,cur:0 ] index 9 [data: ,cur:10] index 10 [data: ,cur:11] index 11 [data: ,cur:0 ] 输入B中第3/4个元素:n step3.1 :元素n在S中不存在,插入之! index 0 [data: ,cur:9 ] index 1 [data: ,cur:2 ] index 2 [data:c ,cur:4 ] index 3 [data:n ,cur:8 ] index 4 [data:e ,cur:5 ] index 5 [data:g ,cur:6 ] index 6 [data:f ,cur:7 ] index 7 [data:d ,cur:3 ] index 8 [data:a ,cur:0 ] index 9 [data: ,cur:10] index 10 [data: ,cur:11] index 11 [data: ,cur:0 ] 输入B中第4/4个元素:f step3.1 :元素f在S中存在,删除之! index 0 [data: ,cur:6 ] index 1 [data: ,cur:2 ] index 2 [data:c ,cur:4 ] index 3 [data:n ,cur:8 ] index 4 [data:e ,cur:5 ] index 5 [data:g ,cur:7 ] index 6 [data:f ,cur:9 ] index 7 [data:d ,cur:3 ] index 8 [data:a ,cur:0 ] index 9 [data: ,cur:10] index 10 [data: ,cur:11] index 11 [data: ,cur:0 ] Process finished with exit code 0