静态链表 c语言实现

转载自:http://blog.csdn.net/jiuyueguang/article/details/12090569


0:实现静态链表的方法

定义一个较大的结构数组作为备用结点空间 ( 即存储池 ) 。当申请结点时,每个结点应含有两个域: data 域和 cursor 域。 data 域用来存放结点的数据信息,此时的 cursor 域不在是指针而是游标指示器,游标指示器指示其后继结点在结构数组中的相对位置 ( 数组下标 )
数组的第 0 个分量可以设计成表的头结点,头结点的 next 域指示了表中第一个结点的位置。表中当前最后一个结点的域为 0 ,表示静态单链表的结束。我们把这种用游标指示器实现的单链表叫做静态单链表, static linked list
静态单链表同样可以借助一维数组来描述。
有趣的是:程序自始至终用的都是同一个数组,那怎么来区分呢?解决方案是:把这个数组 逻辑 分成两个部分(在下面的代码中你可以看到),一部分叫做空闲节点区域,另一部分叫非空闲节点区域(笔者这么叫,你也可以叫别的名字,但是你要想象把这个数组分成两个部分就ok了),前面说了是“逻辑”分隔,那怎么维护这个数组呢?答案是靠cursor域链接下一个节点来维护的。比如看下图(图真难画啊……),那么怎么标注非空闲链表呢?答案是自己定义一个下标来记住非空闲链表头节点下标就ok了。
你的头脑中要有一个场景:一个数组逻辑分成两部分,他们都是通过指针来连接的,空闲链表由空闲头结点来链接起来,非空闲链表由非空闲头结点连接起来,空闲头结点就是数组下标为0的节点,由于每次申请都是从空闲头结点下一个位置申请空闲节点,所以导致非空闲头结点是数组下标为1的节点(这个你在下图或者程序中能够体会到)并且把这个下标记录下来,然后下面的工作就是维护这两个链表了

1:静态链表的实现

  1. 数据结构
    [html]  view plain  copy
    1. #include <stdio.h>  
    2. #define N 100  
    3. typedef struct{  
    4.     char data;  
    5.     int cur;//游标域或者指针域  
    6. }SList;  
    数据结构很好理解,不在赘述。
  2. 初始化
    [html]  view plain  copy
    1. void init_sl(SList slist[]){//初始化成空闲静态链表,  
    2.     int i;  
    3.     for(i=0;i<N-1;i++)  
    4.     {  
    5.         slist[i].cur=i+1;  
    6.     }  
    7.     slist[N-1].cur=0;//最后一个指针域指向0  
    8. }  

  3. 申请分配一个空闲节点
    [html]  view plain  copy
    1. int malloc_sl(SList slist[]){//分配空闲节点  
    2.     int i=slist[0].cur;//总是取头结点之后的第一个空闲结点做分配,同时空闲链表非空,头结点做调整  
    3.     if (i)  
    4.     {  
    5.         slist[0].cur=slist[i].cur;//空闲链表头结点调整指针域  
    6.     }  
    7.     return i;//返回申请到的空闲节点的数组下标  
    8. }  
    注意:这里每次申请空闲节点都是把空闲链表的第一个节点(非头节点)返回,同理在释放空闲节点到空闲链表的的时候也是把空闲节点加到空闲链表头指针的后面第一个的位置
  4. 释放一个空闲节点到空闲链表
    [html]  view plain  copy
    1. void free_sl(SList slist[],int k){//将k节点回收  
    2.     slist[k].cur=slist[0].cur;//总是将回收的节点放在头结点之后  
    3.     slist[0].cur=k;  
    4. }  

2:实例:求集合运算(A-B)U(B-A)的结果

[html]  view plain  copy
  1. int difference_sl(SList slist[],int n){  
  2.     int i,m,q,p;  
  3.     char tmp[2];//为避免出现scanf输入字符出现接受回车符,则采用输入字符串的形式  
  4.     int start,end;//start是哨兵,end指向最后的节点  
  5.     init_sl(slist);//初始化  
  6.     start=malloc_sl(slist);//从空闲链表中取出第一个空闲节点生成链表的头结点  
  7.     //注意区分,现在是有一个空闲链表是slist,里面都是空闲节点,每次申请malloc_sl和free_sl都是操作的是slist  
  8.     //然后非空静态链表,即集合A的链表是由start这个下标指引一直向后走,end指向非空链表的尾节点,  
  9.     //而且你发现start基本上都是1,因为开始的时候slist都是空闲节点,而分配又都是从头结点slist[0]之后的第一个  
  10.     //节点,即slist[1]开始分配,所以start=1  
  11.     end=start;  
  12.     while (n--)  
  13.     {  
  14.         scanf("%s",tmp);  
  15.         i=malloc_sl(slist);  
  16.         slist[i].data=tmp[0];  
  17.         slist[end].cur=i;  
  18.         end=i;//end指针后移  
  19.     }  
  20.     slist[end].cur=0;//这个勿忘!尾节点的指针为空  
  21.     //至此A集合输入完毕,然后处理B集合  
  22.     scanf("%d",&m);  
  23.     while (m--)  
  24.     {  
  25.         scanf("%s",tmp);  
  26.         //从A集合中扫描,如果A中存在tmp,则在A中删除(free_sl),即A-B,如果没有则添加入A,即B-A  
  27.         q=start;//q是p的前驱  
  28.         p=slist[start].cur;  
  29.         while (p!=slist[end].cur&&slist[p].data!=tmp[0])  
  30.         {  
  31.             q=p;  
  32.             p=slist[p].cur;  
  33.         }  
  34.         if (p!=slist[end].cur)//说明在A中找到了tmp,则删除  
  35.         {  
  36.             slist[q].cur=slist[p].cur;//跨过p节点  
  37.             free_sl(slist,p);  
  38.             if (end==p)  
  39.             {  
  40.                 end=q;//如果删除的是尾节点,则修改尾节点指针  
  41.             }  
  42.         }else{  
  43.             i=malloc_sl(slist);  
  44.             slist[i].data=tmp[0];  
  45.             slist[i].cur=slist[end].cur;  
  46.             slist[end].cur=i;//插在end后,end位置不变,因为end是标志集合A的结束,但是这里你也可以变化end指针,就是加上end=i即可  
  47.         }  
  48.     }  
  49.     return start;  
  50. }  
加上一个打印的函数
[html]  view plain  copy
  1. void print_sl(SList slist[],int start){  
  2.     int p=slist[start].cur;  
  3.     while (p)  
  4.     {  
  5.         printf("%c ",slist[p].data);  
  6.         p=slist[p].cur;  
  7.     }  
  8.     printf("\n");  
  9. }  

加上一个main函数
[html]  view plain  copy
  1. int main(){  
  2.     int n,start;  
  3.     SList slist[N];  
  4.     freopen("1.txt","r",stdin);  
  5.     //该程序是求(A-B)U(B-A)集合运算  
  6.     while (scanf("%d",&n)==1)  
  7.     {  
  8.         start=difference_sl(slist,n);  
  9.         print_sl(slist,start);  
  10.     }  
  11.     fclose(stdin);  
  12.     return 0;  
  13. }  

目录(?)[+]

[html]  view plain  copy
  1.   

0:实现静态链表的方法

定义一个较大的结构数组作为备用结点空间 ( 即存储池 ) 。当申请结点时,每个结点应含有两个域: data 域和 cursor 域。 data 域用来存放结点的数据信息,此时的 cursor 域不在是指针而是游标指示器,游标指示器指示其后继结点在结构数组中的相对位置 ( 数组下标 )
数组的第 0 个分量可以设计成表的头结点,头结点的 next 域指示了表中第一个结点的位置。表中当前最后一个结点的域为 0 ,表示静态单链表的结束。我们把这种用游标指示器实现的单链表叫做静态单链表, static linked list
静态单链表同样可以借助一维数组来描述。
有趣的是:程序自始至终用的都是同一个数组,那怎么来区分呢?解决方案是:把这个数组 逻辑 分成两个部分(在下面的代码中你可以看到),一部分叫做空闲节点区域,另一部分叫非空闲节点区域(笔者这么叫,你也可以叫别的名字,但是你要想象把这个数组分成两个部分就ok了),前面说了是“逻辑”分隔,那怎么维护这个数组呢?答案是靠cursor域链接下一个节点来维护的。比如看下图(图真难画啊……),那么怎么标注非空闲链表呢?答案是自己定义一个下标来记住非空闲链表头节点下标就ok了。
你的头脑中要有一个场景:一个数组逻辑分成两部分,他们都是通过指针来连接的,空闲链表由空闲头结点来链接起来,非空闲链表由非空闲头结点连接起来,空闲头结点就是数组下标为0的节点,由于每次申请都是从空闲头结点下一个位置申请空闲节点,所以导致非空闲头结点是数组下标为1的节点(这个你在下图或者程序中能够体会到)并且把这个下标记录下来,然后下面的工作就是维护这两个链表了

1:静态链表的实现

  1. 数据结构
    [html]  view plain  copy
    1. #include <stdio.h>  
    2. #define N 100  
    3. typedef struct{  
    4.     char data;  
    5.     int cur;//游标域或者指针域  
    6. }SList;  
    数据结构很好理解,不在赘述。
  2. 初始化
    [html]  view plain  copy
    1. void init_sl(SList slist[]){//初始化成空闲静态链表,  
    2.     int i;  
    3.     for(i=0;i<N-1;i++)  
    4.     {  
    5.         slist[i].cur=i+1;  
    6.     }  
    7.     slist[N-1].cur=0;//最后一个指针域指向0  
    8. }  

  3. 申请分配一个空闲节点
    [html]  view plain  copy
    1. int malloc_sl(SList slist[]){//分配空闲节点  
    2.     int i=slist[0].cur;//总是取头结点之后的第一个空闲结点做分配,同时空闲链表非空,头结点做调整  
    3.     if (i)  
    4.     {  
    5.         slist[0].cur=slist[i].cur;//空闲链表头结点调整指针域  
    6.     }  
    7.     return i;//返回申请到的空闲节点的数组下标  
    8. }  
    注意:这里每次申请空闲节点都是把空闲链表的第一个节点(非头节点)返回,同理在释放空闲节点到空闲链表的的时候也是把空闲节点加到空闲链表头指针的后面第一个的位置
  4. 释放一个空闲节点到空闲链表
    [html]  view plain  copy
    1. void free_sl(SList slist[],int k){//将k节点回收  
    2.     slist[k].cur=slist[0].cur;//总是将回收的节点放在头结点之后  
    3.     slist[0].cur=k;  
    4. }  

2:实例:求集合运算(A-B)U(B-A)的结果

[html]  view plain  copy
  1. int difference_sl(SList slist[],int n){  
  2.     int i,m,q,p;  
  3.     char tmp[2];//为避免出现scanf输入字符出现接受回车符,则采用输入字符串的形式  
  4.     int start,end;//start是哨兵,end指向最后的节点  
  5.     init_sl(slist);//初始化  
  6.     start=malloc_sl(slist);//从空闲链表中取出第一个空闲节点生成链表的头结点  
  7.     //注意区分,现在是有一个空闲链表是slist,里面都是空闲节点,每次申请malloc_sl和free_sl都是操作的是slist  
  8.     //然后非空静态链表,即集合A的链表是由start这个下标指引一直向后走,end指向非空链表的尾节点,  
  9.     //而且你发现start基本上都是1,因为开始的时候slist都是空闲节点,而分配又都是从头结点slist[0]之后的第一个  
  10.     //节点,即slist[1]开始分配,所以start=1  
  11.     end=start;  
  12.     while (n--)  
  13.     {  
  14.         scanf("%s",tmp);  
  15.         i=malloc_sl(slist);  
  16.         slist[i].data=tmp[0];  
  17.         slist[end].cur=i;  
  18.         end=i;//end指针后移  
  19.     }  
  20.     slist[end].cur=0;//这个勿忘!尾节点的指针为空  
  21.     //至此A集合输入完毕,然后处理B集合  
  22.     scanf("%d",&m);  
  23.     while (m--)  
  24.     {  
  25.         scanf("%s",tmp);  
  26.         //从A集合中扫描,如果A中存在tmp,则在A中删除(free_sl),即A-B,如果没有则添加入A,即B-A  
  27.         q=start;//q是p的前驱  
  28.         p=slist[start].cur;  
  29.         while (p!=slist[end].cur&&slist[p].data!=tmp[0])  
  30.         {  
  31.             q=p;  
  32.             p=slist[p].cur;  
  33.         }  
  34.         if (p!=slist[end].cur)//说明在A中找到了tmp,则删除  
  35.         {  
  36.             slist[q].cur=slist[p].cur;//跨过p节点  
  37.             free_sl(slist,p);  
  38.             if (end==p)  
  39.             {  
  40.                 end=q;//如果删除的是尾节点,则修改尾节点指针  
  41.             }  
  42.         }else{  
  43.             i=malloc_sl(slist);  
  44.             slist[i].data=tmp[0];  
  45.             slist[i].cur=slist[end].cur;  
  46.             slist[end].cur=i;//插在end后,end位置不变,因为end是标志集合A的结束,但是这里你也可以变化end指针,就是加上end=i即可  
  47.         }  
  48.     }  
  49.     return start;  
  50. }  
加上一个打印的函数
[html]  view plain  copy
  1. void print_sl(SList slist[],int start){  
  2.     int p=slist[start].cur;  
  3.     while (p)  
  4.     {  
  5.         printf("%c ",slist[p].data);  
  6.         p=slist[p].cur;  
  7.     }  
  8.     printf("\n");  
  9. }  

加上一个main函数
[html]  view plain  copy
  1. int main(){  
  2.     int n,start;  
  3.     SList slist[N];  
  4.     freopen("1.txt","r",stdin);  
  5.     //该程序是求(A-B)U(B-A)集合运算  
  6.     while (scanf("%d",&n)==1)  
  7.     {  
  8.         start=difference_sl(slist,n);  
  9.         print_sl(slist,start);  
  10.     }  
  11.     fclose(stdin);  
  12.     return 0;  
  13. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值