异质链表(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
- 异质链表(C语言实现)
- 栈(C语言实现)
- 俄罗斯方块(C语言实现)
- 人事管理系统(C语言实现)
- 链表(C语言实现)
- 排序(C语言实现)
- C 语言实现文件传输 (socket实现)
- 【C语言】C语言字符串函数实现(一)
- 【C语言】C语言字符串函数实现(二)
- 【c语言】c语言实现顺序表(静态)
- 【C语言】实现注释转换(c->c++)
- c语言实现注释转换(c转为c++)
- 自己实现库函数strstr() (c 语言)
- 贪心算法(C语言实现)
- 判断素数问题(C语言实现)
- 静态数组实现队列(C语言)
- 静态链表实现(c语言)
- 大整数乘法(C语言实现)
- poj 2236 Wireless Network 并查集
- Android环境搭建的那些奇葩问题
- Aop
- 输入型参数(const)与输出型参数
- InnoDB还是MyISAM
- 异质链表(C语言实现)
- 使用Segue在两个UIViewController之间建立联系-NavigationController
- 《leetCode》:Valid Sudoku
- 象行中国9月份9个城市PPT分享(一)
- android 生成 QR_CODE 码 PFD_417码 CODE_36码
- Java BIO、NIO、AIO 学习
- Go语言并发之美
- nyoj 找点 891 (贪心)
- Scala 读取网页数据测试及备忘