异质链表(C语言实现)

来源:互联网 发布:新疆行知中学学费 编辑:程序博客网 时间:2024/04/26 04:37

  用C语言实现多态性的基本思想是使用void*指针,在存储链表结点值的时候将地址存入。

  也就是说结点中存储的值并不是具体的值,而是一个地址,由于这个地址是main中的本地变量,所以不用担心它会被摧毁。

  在读取的时候,进行强制类型转换即可。

  在老师布置异质链表作业的时候,参考了网上很多代码,基本上都是通过传入类型,再在函数内部进行链表创建。这样的写法对于main函数依赖很大,无法实现函数的模块化(也就是说它不能独立存在,必须依赖main函数),个人感觉并不是那么可取。而且链表的值必须通过用户动态输入得到,局限性较大,无法实现传入已有的值。在这一块卡了很久,也查了非常多资料,尤其是void*相关的知识。

  不过对于头结点的处理比较麻烦,因为传入链表的时候只能拷贝一个指针,对拷贝的指针进行修改,比如加入头结点,并不会影响到原链表。这时候必须强制用户用返回值来接收新得到的链表指针,或者还有一种解决办法是传入指向链表指针的指针,但是这样也要强迫用户传入指向链表指针的指针。总之非常麻烦,这个问题暂时还没有完美解决。在C++中就很简单,传入引用就可以了。

/* @fish1996 2015/09/30     *//* 数字媒体技术1402*/#include<stdio.h>#include<stdlib.h>enum{Char,Double,Int};/*链表的声明*/ typedef struct ListNode{void *data;int type;struct ListNode *next;}*List;/*得到链表的长度*/int Length(List PtrL); /*创建一个空链表*/ List Create();/*在表头插入*/ List InsertFro(void *x,int type,List PtrL);/*在第k个位置插入*/ List InsertKth(void *x,int k,int type,List PtrL);/*在表尾插入*/ List InsertBack(void *x,int type,List PtrL);/*查找第k个元素*/ List FindKth(int k,List PtrL); /*查找值为x的元素,返回下标*/ int FindXIndex(void *x,int type,List PtrL);/*查找值为x的元素,返回节点*/ List FindXNode(void *x,int type,List PtrL);/*删除链表头*/ List DeleteFro(List PtrL);/*删除下标为k的元素*/ List DeleteKth(int k,List PtrL);/*删除值为x的元素*/ List Delete(void *x,List PtrL);/*遍历链表输出*/void Print(List PtrL);/*链表销毁*/List Destroy(List PtrL);/*两个链表的合并*/List Union(List p,List s);/*链表的逆置*/List Reverse(List p);/* 创建一个空的链表                                  */ List Create(){List L = NULL;  /*设立指向NULL的指针*/ return L;}/* 计算链表长度                                      */int Length(List PtrL){    int length=0;List p=PtrL;while(p){  /*从第一个结点开始移动指针位置计算长度*/ p=p->next; length++;} return length;}/* 在表头插入                                        *//* 使用说明:                                        *//* 要得到插入表头的链表,只能在返回值中得到          *//* 因为这里没有传指向指针的指针,原指针并没有被改变  *//* 传入的是元素x的地址,所以必须是明确定义且赋值的变量*//* correct: p=InsertFro(&x,Int,p);                   *//* error: p=InsertFro(x,Int,p);                      */ /* error: InsertFro(&x,Int,p);                       */ /* error:p=InsertFro(1,Int,p)                       */ List InsertFro(void *x,int type,List PtrL){List p; /*申请结点内存并赋值*/ p=(List)malloc(sizeof(struct ListNode));p->data=x;/*data指针等于x指针*/ p->type=type;/*存储类型*/ p->next=PtrL;/*让该结点指向原链表*/ return p;} /* 在第k个位置插入                                    */ /* 使用说明:                                         */ /* 要得到插入表头的链表,即k=1时,只能在返回值中得到  *//* 因为这里没有传指向指针的指针,原指针并没有被改变   *//* 其余情况可以不使用返回值                           *//* 传入的是元素x的地址,所以必须是明确定义且赋值的变量 *//* correct: p=InsertKth(&x,1,Int,p);                  *//* correct: p=InsertKth(&x,2,Int,p);                  *//* correct: InsertKth(&x,2,Int,p);                    *//* error: p=InsertKth(x,1,Int,p);                     */ /* error: InsertKth(&x,1,Int,p);                      */ /* error:p=InsertKth(1,1,Int,p)                      */ List InsertKth(void *x,int k,int type,List PtrL){List p,s;int length;if(k==1)return InsertFro(&x,type,PtrL);/*k=1调用已有函数,实现代码重用*/ p=FindKth(k-1,PtrL);/*找到要删除结点的上一个结点*/ if(!p){printf("Error: illegal index\n");    return PtrL;}/*不存在上一个结点*/s=(List)malloc(sizeof(struct ListNode));/*为插入元素分配内存*/ s->next=p->next;/*先让新结点指向它前一个元素的下一个元素*/ p->next=s;/*再让前一个元素指向新节点*/s->data=x;/*data指针等于x指针*/ s->type=type;/*存储类型*/ return PtrL;}/*在表尾插入                                          */ /* 使用说明:                                         */ /* 可以不使用返回值                                   *//* 传入的是元素x的地址,所以必须是明确定义且赋值的变量 *//* correct: p=InsertBack(&x,Int,p);                   *//* correct: InsertBack(&x,Int,p);                     *//* error: p=InsertBack(x,Int,p);                      *//* error:p=InsertBack(1,Int,p)                       */ List InsertBack(void *x,int type,List PtrL){int k=Length(PtrL); /*得到链表长度*/ return InsertKth(x,k+1,type,PtrL); /*调用已有函数,实现代码重用*/ }/* 查找第k个元素,返回结点                            */ /* 使用说明:                                         */ /* correct: s=FindKth(2,p);                           */List FindKth(int k,List PtrL){List p=PtrL;int count=1;while(count!=k&&p){/*当下标不为k并且p不为NULL*/ p=p->next; /*移动结点*/ count++; /*记录当前下标*/}if(!p){printf("Error: Not found\n");}return p;}/*查找值为x的元素,返回下标                            *//* 使用说明:                                         */ /* 由于void*的限制,该函数实现功能较差                *//* 传入的是元素x的地址,所以必须是明确定义且赋值的变量 *//* 所以在传入特定值的时候必须先将其定义               *//* correct: index=FindXIndex(&x,Int,p);               *//* error:index=FindXIndex(1,Int,p)                   */  int FindXIndex(void *x,int type,List PtrL){int count=1;/*记录当前下标*/ List p=PtrL;switch(type){ /*选择类型执行对应操作*/ case Int:        while(p&&(*(int*)p->data!=*(int*)x||p->type!=Int)){        /*判断p是否为空,值是否相等,类型是否匹配*/        p=p->next;        count++;            }            break;        case Double:     while(p&&(*(double*)p->data!=*(double*)x||p->type!=Double)){     p=p->next;     count++;            }break;case Char:        while(p&&(*(char*)p->data!=*(char*)x||p->type!=Char)){        p=p->next;        count++;            }            break;       }if(!p){printf("Error: Not found\n");return 0;}return count;} /*查找值为x的元素,返回结点                            *//* 使用说明:                                         */ /* 由于void*的限制,该函数实现功能较差                *//* 传入的是元素x的地址,所以必须是明确定义且赋值的变量 *//* 所以在传入特定值的时候必须先将其定义               *//* correct: p=FindXNode(&x,Int,p);                    *//* error:p=FindXNode(1,Int,p)                        */ List FindXNode(void *x,int type,List PtrL){List p;int index;index=FindXIndex(&x,type,PtrL);/*调用已有函数,实现代码重用*/if(index==0)return NULL;p=FindKth(index,PtrL);return p;}/*删除链表头                                          *//* 使用说明:                                         */ /* 要使用返回值得到删除链表头的链表                   *//* 因为这里没有传指向指针的指针,原指针并没有被改变   *//* correct: p=DeleteFro(p);                           *//* error:DeleteFro(p);                              */ List DeleteFro(List PtrL){List s=PtrL;/*记录表头位置*/if(PtrL)PtrL=PtrL->next;/*如果链表不为空,向后移动一位*/ else return PtrL;free(s); /*释放表头空间*/ return PtrL; /*返回删除表头的链表*/} /*删除下标为k的元素                                   */ /* 使用说明:                                         */ /* k=1时要使用返回值                                  *//* 其余可以使用返回值,也可以不使用                   *//* correct: p=DeleteKth(2,p);                         *//* correct:DeleteKth(2,p);                          */ /* error: DeleteKth(1,p);                             */ List DeleteKth(int k,List PtrL){List p,s;if(k==1)return DeleteFro(PtrL);/*调用已有函数,实现代码重用*/p=FindKth(k-1,PtrL);/*找到要删除结点的前一个结点*/ if(p==NULL||p->next==NULL){printf("Error: illegal index\n");return PtrL;}/*如果要删除结点或前一个结点不存在,返回原链表*/ s=p->next;/*s指向待删除结点*/ p->next=s->next;/*待删除结点前一个结点指向待删除结点下一个结点*/ free(s); /*释放待删除结点空间*/ return PtrL;}/*删除链尾                                            */ /* 使用说明:                                         */ /* 可以使用返回值,也可以不使用                       *//* correct: p=DeleteBack(p);                          *//* correct:DeleteBack(p);                           */ List DeleteBack(List PtrL){List p;int len=Length(PtrL);return DeleteKth(len,PtrL);}/*遍历链表输出                                        *//* 使用说明:                                         */ /* correct: Print(p);                                 */ void Print(List PtrL){List p=PtrL;while(p){/*根据类型做对应的输出*/switch(p->type){case Int:printf("%d ",*(int*)p->data);break;case Char:printf("%c ",*(char*)p->data);break;case Double:printf("%lf ",*(double*)p->data);break;}p=p->next;/*移动指针位置*/ }printf("\n");}/*只输出当前结点的值                                  *//* 使用说明:                                         */ /* correct: PrintNow(p);                              */ void PrintNow(List PtrL){List p=PtrL;if(p){/*根据类型做对应的输出*/switch(p->type){case Int:printf("%d ",*(int*)p->data);break;case Char:printf("%c ",*(char*)p->data);break;case Double:printf("%lf ",*(double*)p->data);break;}}printf("\n");}/* 链表销毁                                           *//* 使用说明:                                         */ /* 要得到销毁后的链表,需要使用返回值                 *//* 因为这里没有传指向指针的指针,原指针并没有被改变   *//* correct: p=Destroy(p);                             */ /* error: Destroy(p);                                 */ List Destroy(List PtrL){List q,p=PtrL;while(p){q=p->next;/*记录p的下一个结点位置*/free(p);/*释放p的内存空间*/ p=q;/*p指向下一个结点*/ }return p;}/* 两个链表的合并                                     *//* 使用说明:                                         */ /* 按第一个链表在前,第二个链表在后的顺序合并         *//* 要得到合并后的链表,需要使用返回值                 *//* 因为这里没有传指向指针的指针,原指针并没有被改变   *//* correct: p=Union(p1,p2);                           */ /* correct: p1=Union(p1,p2);                          *//* error: Union(p1,p2)                                */ List Union(List PtrL1,List PtrL2){List p;int len;len=Length(PtrL1);/*得到第一个链表长度*/ p=FindKth(len,PtrL1);/*得到第一个链表的尾结点*/ p->next=PtrL2;/*让第一个链表的尾结点指向第二个链表的头结点*/ return PtrL1; }/* 链表的逆置                                         *//* 使用说明:                                         */ /* 要得到逆序后的链表,需要使用返回值                 *//* 因为这里没有传指向指针的指针,原指针并没有被改变   *//* correct: p=Reverse(p);                             */ /* error: Reverse(p)                                  */List Reverse(List PtrL){List now,next,prev,head,tmp;if(!PtrL)return PtrL; next=PtrL;/*next指向第一个元素*/ now=next->next; /*now指向第二个元素*/ next->next=NULL;/*因为next将会是最后一个结点,将其下一个结点设为NULL*/ while(now){prev=now->next;/*记录now的下一轮循环的位置*/ now->next=next;/*逆序过程,让后一个结点指向前一个结点*/next=now;/*next向后移一位*/ now=prev;/*now向后移一位*/ }return next;}int main(){List p=Create();List l=Create();int u=1996;int x=1;int y=1;char t='b';double d=0.1;char a='a'; l=InsertFro(&u,Int,l);printf(">> Insert element 1 in front of the list:\n");p=InsertFro(&x,Int,p);Print(p);printf("\n");printf(">> Insert element b with index 2:\n");    InsertKth(&t,2,Char,p);    Print(p);    printf("\n");        printf(">> Insert element 0.1 at the back of the list:\n");    InsertBack(&d,Double,p);    Print(p);    printf("\n");printf(">> The length of the list:\n%d\n",Length(p));printf("\n");printf(">> Find the index of element a in the list:\n");printf("%d\n",FindXIndex(&a,Char,p)); printf("\n");printf(">> Delete element with index 6:\n");DeleteKth(6,p);printf("\n");printf(">> Insert element 1 with index 5:\n");InsertKth(&x,5,Int,p);printf("\n"); p=Reverse(p);printf(">> After reverse:\n");Print(p);printf("\n");List q=FindKth(2,p);printf(">> The second element of the list is:\n");PrintNow(q);printf("\n");printf(">> The index of the value 1 is:\n");printf("%d\n",FindXIndex(&y,Int,p));printf("\n");printf(">> Found the element with index 4:\n");FindKth(4,p);printf("\n");p=Union(p,l);printf(">> After connect two lists:\n");Print(p);printf("\n");p=DeleteFro(p);printf(">> Delete the first element:\n");Print(p);printf("\n");    DeleteKth(2,p);printf(">> Delete element with index 2:\n");Print(p);printf("\n");DeleteBack(p);printf(">> Delete the last element:\n");Print(p);printf("\n");p=Destroy(p);printf(">> After destroy:\n");Print(p);printf("\n");    return 0;}


4 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 4.2货车拉缸了怎么办 工作中与同事发生矛盾怎么办 和领导关系闹僵怎么办 内倒窗户卡住了怎么办 支付宝存在安全风险怎么办 地铁车站空调坏了怎么办 面试防汛值班发生灾情你怎么办 怀孕上班路途太远怎么办 硕士错过校招应该怎么办 收银员收多了钱怎么办 商铺贷款批不了怎么办 铁路局的门面乱收房租怎么办 酒店夜审房费多过怎么办 夜审房价录多了怎么办 做工地拿不到钱怎么办 赢了官司拿不到钱怎么办 工地上拿不到钱怎么办 做了工拿不到钱怎么办 高速公路上车没油了怎么办 高铁乘务员年龄大了怎么办 总公司跑路了分公司怎么办 坐车久了耳朵懵怎么办 过完隧道耳朵疼怎么办 护照还在大使馆需要出国怎么办 护照在大使馆不返回怎么办 美国面签迟到了怎么办 成都美签迟到了怎么办 签证电调没人接怎么办 单位没有抬头纸怎么办在职证明 出国签证无银行流水怎么办 铁路职工得癌症后工作怎么办 去泰国不会泰语和英语怎么办 签证状态一直没有更新怎么办 简理财不能身份信息确认怎么办 德国领事馆没有收到预约邮件怎么办 父母一方带孩子英国签证怎么办 去韩国自由行签证怎么办 韩国自由行签证的该怎么办 法院离婚判决书没了怎么办 离婚判决书对方没收到怎么办 法院判离怎么办离婚证