线性表->链式存储->单链表

文字描述:

为了表示前后两个数据元素的逻辑关系,对于每个数据元素,除了存储其本身的信息之外(数据域),还需存储一个指示其直接后继的信息(即直接后继的存储位置,指针域)。

示意图:

算法分析:

在单链表中插入和删除元素时,主要是改变指针的值,其时间复杂度为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

猜你喜欢

转载自www.cnblogs.com/aimmiao/p/10391917.html