c语言共用体实现任意数据类型的单链表

大一上学期时,老师简单讲了单链表的原理,但没有让我们练习。正好疫情封校,闲来无事,就想自己做一个单链表。

我看了书上添加节点的函数,剩下的就是我自由发挥了。我照着c#的list方法给我的单链表做功能:

(capacity和count方法没做,这个直接用sizeof和调用结构体属性就能做到)

此外,我的单链表可支持任意数据类型,书上只是用int型做了示范。我完成这个需求的方法很奇怪,用的是共用体,我在网上没找到和我一样的方法,所以在此分享给各位码友。

好了,准备开始咯!

首先,先说一下单链表的原理。一个结构体link里有两个属性,一个是数据data,一个是link指针,使用时data存数据,指针指向下一个结构体link。如此往复,一节连着一节,这样就实现了单链表:

typedef struct link
{
	var data;//数据内容 
	struct link *next;//下一个节点的指针 
} link;

这里我数据用的类型是我自定义的共用体类型var,定义如下:

union v//设置共用体,长度为四字节 
{
	short var_short;
	char var_char;
	int var_int;
	float var_float;
	unsigned char var_byte;
	unsigned int var_uint;
	
} ;
typedef union v var;

(里面是一些常用的数据类型)

和书上不一样的地方,我还建了一个结构体list,用于存放单链表的头指针、数据类型、节点数,我的函数操作全是操作这个结构体,我感觉这样更简洁,更一目了然:

typedef struct list
{
	type dataType;//数据类型 
	link *head;//链表头指针 
	unsigned int number;//节点个数 
} list;

其中,数据类型我建了一个枚举类型。因为在输出共用体的时候,必须知道他是什么数据类型才能输出正确的值,之后的函数我因为这个多走了不少弯路。想实现任意数据类型的单链表,我看网上的方法用的是void*指针存,但是我没看懂,所以最后还是用了共用体。

typedef enum type//枚举类型,用于传递变量类型 
{
	var_short,
	var_char,
	var_float,
	var_int,
	var_byte,
	var_uint
} type;

 好了,现在准备工作已经完成,接下来就让我们写方法吧!

//函数功能:初始化 
list *ListInit(type mytype)//数据类型 
{
	list *newlist=(list*)malloc(sizeof(list));//新建list类型 
	newlist->head=NULL;//指向空地址 
	newlist->dataType=mytype;//获得数据类型 
	newlist->number=0;//列表数量 
	return newlist;//返回newlist
	
}

//函数功能:添加元素至末尾 
void ListAdd(list *mylist,var data)//list结构体指针,数据内容 
{
	link *p=NULL,*pr=mylist->head;//新建link指针,p将指向新内存,pr获得头指针 
	p=(link*)malloc(sizeof(link));//新建内存 
	if(mylist->head==NULL)//列表为空的情况 
		mylist->head=p;//直接获得一个元素 
	else//存在元素的情况 
		{
			while(pr->next!=NULL)//遍历链表,找到表的尾指针 
				pr=pr->next;
			pr->next=p;//末节点指针指向新节点 
		}
	p->data=data;//获得数据内容 
	p->next=NULL;//将新节点置为表尾 
	mylist->number++;//节点数 +1  
}

//函数功能:遍历链表,输出数据内容 
void ListDisplay(list *mylist)//list结构体指针
{
	link *pr=mylist->head;//pr获得头指针 
	int i=1;
		if(mylist->head==NULL)//链表为空 
		{
			printf("链表为空\n");
		}
		else //链表不为空 
		{
			ListDisplay_printType(mylist);//输出此链表类型、节点个数 
			while(1)
			{
				printf("第%d个节点数据为:",i);//输出第一个节点 
				ListDisplay_printData(pr->data,mylist->dataType);//输出节点内容 
				printf("\n"); 
				if(pr->next==NULL)//遍历链表,找到表的尾指针时跳出循环 
					break;
				else
				{
					pr=pr->next;
					i++; 
				}
					
			}
		}
	
}

void ListDisplay_printData(var data,type dataType)
{
	switch(dataType)
	{
		case var_short:
		case var_int:
		case var_byte:
		case var_uint:
			printf("%d",data);break;
		case var_char:
			printf("%c",data.var_char);break;
		case var_float:
			printf("%f",data.var_float);break;
		
	}
}

void ListDisplay_printType(list *mylist)
{
	switch(mylist->dataType)
	{
		case var_short:printf("单链表是short型");break;
		case var_int:printf("单链表是int型");break;
		case var_byte:printf("单链表是byte型");break;
		case var_uint:printf("单链表是uint型");break;
		case var_char:printf("单链表是char型");break;
		case var_float:printf("单链表是float型");break;
		
	}
	printf(",含有%d个元素\n",mylist->number);
}

//函数功能:将数据插入链表任意位置 
int ListInsert(list* mylist,int num,var data)//list结构体指针,插入位置,数据内容 
{
	link *pr=mylist->head,*p=NULL,*temp=NULL;
	p=(link*)malloc(sizeof(link));//新内存 
	int i;
	
	if(num>mylist->number)//判断位置是否合理 
	{
		free(p);
		return 0;
	}
	else
	{
		for(i=1;i<num-1;i++)// 遍历链表,在插入的节点之前跳出循环
			pr=pr->next;
		temp=pr->next;//临时指针变量存下一个节点地址 
		pr->next=p;//下一个节点指针变为新建指针 
		p->data=data;//赋值 
		p->next=temp;//新指针获得临时指针 
		mylist->number++;//节点数 +1		
		return 1;
	}
}

//查找链表中任意元素 
var ListIndex(list *mylist,int num)//list结构体指针 ,元素编号 
{
	link *pr=mylist->head;//pr获得头指针 
	int i=1;
	var data;
	data.var_int=0;
	if(num>mylist->number)//判断位置是否合理 
	{
		return data;
	}
		
	else //链表不为空 
	{	
		while(1)
		{
			if(i==num)//遍历链表,找到指定节点时跳出循环 
				break;
			else
			{
				pr=pr->next;
				i++; 
			}				
		}
	return pr->data;//返回数据 	
	}
	
}

//删除任意元素 
int ListRemoveAt(list *mylist,int num)//list结构体指针,元素编号 
{
	link *pr=mylist->head,*temp=NULL;//pr获得头指针 
	int i=1;
	if(num>mylist->number)//判断位置是否合理 
		return 0;
	else
	{
		while(1)
		{
			if(i==num-1)//遍历链表,找到指定节点的前一个节点时跳出循环 
				break;
			
			else
			{
				pr=pr->next;
				i++; 
			}	
		} 
	temp=pr->next;//获得指定节点指针 
	pr->next=pr->next->next;//将指定节点的前一节点指向指定节点的后一节点 
	free(temp);	//内存回收 
	mylist->number--;//节点数-1	
	return 1;		
	}
}

int DataCompare(var data1,var data2,type dataType)
{
	int re;
	switch(dataType)
	{
		
		case var_short:re=data1.var_short-data2.var_short;break;
		case var_int:re=data1.var_int-data2.var_int;break;
		case var_byte:re=data1.var_byte-data2.var_byte;break;
		case var_uint:re=data1.var_uint-data2.var_uint;break;
		case var_char:re=data1.var_char-data2.var_char;break;
		case var_float:re=data1.var_float-data2.var_float;break;
	
	}
	return re;
}

(这是一个将两个共用体数据相减的函数,用于之后的比较数据大小,看到多麻烦了吧)

//函数功能:查找特定元素位置 
int ListIndexOf(list *mylist,var data)//list结构体指针,元素数据 
{
	link *pr=mylist->head;//pr获得头指针 
	int i=1;
	while(1)
	{
		if(!DataCompare(pr->data,data,mylist->dataType))//如果节点数据与查找数据相等 
			return i;//返回序号 
		if(pr->next==NULL)//遍历链表,找到表的尾指针跳出循环 
			return 0;		
		else
		{
			pr=pr->next;
			i++; 
		}	
	} 
}

//函数功能:从大到小排列元素 
void ListSort(list *mylist)//list结构体指针
{
	link *pr=mylist->head,*p=NULL,*templink=NULL;//pr获得头指针  
	var *array=NULL,temp;//建立var类型数组和一个临时变量 
	int i=0,j;
	array=(var*)malloc(sizeof(var)*(mylist->number-1));//分配内存空间 
	while(1)//使array数组获得链表的所有数据,销毁原链表 
	{
		array[i]=pr->data; 
		templink=pr;
		if(pr->next==NULL)
		{
			free(templink);
			break;
		}
		else
		{
			
			pr=pr->next;
			free(templink);
		}
		
		i++;
	}
	
	for(i=0;i<mylist->number-1;i++)//在array数组将数据排序 
	{
		for(j=i+1;j<mylist->number;j++)
		{
			if(DataCompare(array[i],array[j],mylist->dataType)>0)
			{
				temp=array[i];
				array[i]=array[j];
				array[j]=temp;
			}
		}	
	}
	//新建链表,将排好序的数组赋值给新链表 
	p=(link*)malloc(sizeof(link));
	p->data=array[0];
	p->next=NULL;
	mylist->head=p; 
	pr=mylist->head;
	for(i=1;i<mylist->number;i++)
	{
		p=(link*)malloc(sizeof(link));
		p->data=array[i];
		p->next=NULL;
		pr->next=p;
		pr=pr->next;
	}
	free(array);//销毁数组 
	
	
}

(最后这个排序是我自己想到的,就是用一个数组存单链表之后的数据,然后操作数组进行排序,最后以排完序的数组建立新的链表)

好了,到此单链表就写完了。这个项目耗时一周,就是每天写一点。其中还是走了不少弯路的,我对指针有了更加深刻的认识,所以对我的提升还是蛮大的。

运行成功的那一刻,真的非常开心!!

我不知道别人怎么想的,反正我一直把写代码当作一件快乐的事,没有什么事情比创作更有意思了。

继续努力!!!

文件已打包上传GitHub

https://github.com/mamawhes/list

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值