您的位置:首页 > 编程语言 > C语言/C++

异质链表(C语言实现)

2015-11-11 22:32 591 查看
  用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: