初探链表结构

   学习c语言的人都知道,作为c语言里面的一个重要的基础数据结构,链表有着不可忽视的作用。它既承接了前面的数组,又启示了接下来要学到的其它数据结构。但是链表也成为许多人学习c语言和数据结构上的一个难点。我也在此纠结许久,今天将自己的想法写出,希望能和诸位共赏链表之妙。

  所谓的链表,从字面上理解,无非就是将一串数想链子一样一个个的串起来,一个接着一个,通过上一个能找到下一个。特别地,最后一个没有下一个,可以想象成“空”跟在最后一个后面。其实它构建的主要思想就是通过指针来建立前与后的联系,由于指针的加入,链表相比于其它表也就有了一个明显的优点——不用连续存储。因此在插入或者删除时,也不用整体移动表(此处可参考数组的插入和删除,孰优孰劣,一比便知)。链表要达成前后紧密联系的效果,关键在它的每个单元上面。对于链表的每个结构,它主要分为两个部分,前一个部分主要是存储这个结构的主要信息(这里面可以是几个int char类型的量,也可以是自定义类型的量,还可以是结构体),后一个部分是指针,它指向下一个结构(对于最后一个结构,这个部分为空指针)。值得注意的是,这里面的每一个指针都是指向一个结构的,而不是我们常见的基本数据类型,声明的时候别犯错误。对于构建一个链表的基本思想大致就是这些。现在我们根据一个具体实例来看看。写一个函数,这个函数的作用是构建一个链表,对于每一个链表结构,它的数据部分包括一个学生的考试序号以及她或他的考试成绩,当输入考试成绩为非正数时停止输入,考试成绩可以为小数。仔细思考过后,这个问题只要按部就班也没多大问题。下面是代码。(若是之前没有见过typedef,可以考虑去查下,因为这个使用还是挺广泛的)

typedef struct listnode{
    int iNum;
    double score;
    struct listnode * pNodeNext;
	
}* node;//构建链表的每一个单元
struct listnode * create(){//创建链表 
	int tempiNum;
	double tempscore;
	node temphead=NULL,tempptr,temptail=NULL;//声明头结点和尾结点,不断更新尾结点达到加入链表的目的 
	printf("Input number and score:\n");
	scanf("%d",&tempiNum);
	scanf("%lf",&tempscore);//只有分数大于零时才为有效分数,才可以向链表中加入 
	while(tempscore>0)
	{
		tempptr=(struct listnode *)malloc(sizeof(struct listnode));//此处为帮新的要加入的结点开辟一个空间,这些结点不一定要在
		//链表中连续储存,但是它们能够找到彼此(通过指针)
		tempptr->iNum=tempiNum;
		tempptr->score=tempscore;
		tempptr->pNodeNext=NULL;
		if(!temphead)
		   	{
		   		temphead=tempptr;//注意这些指针指向的是一个结构体,头指针指向第一个元素
		   		temptail=tempptr;
				} 
		else
			{
				temptail -> pNodeNext=tempptr;//更新尾指针 
			temptail=tempptr;
			}
		printf("Input number and score:\n");
	    scanf("%d",&tempiNum);
	    scanf("%lf",&tempscore);
	}
	return temphead;
}
创建链表的函数已经写好了,这个函数的返回值为头指针,便于下一步的操作。对于一个链表来说,仅仅创建出来是远远不够的,我们还要对它进行一系列的操作,既然能创建出来,我们想要看到就必须写出一个输出函数。也就是说将链表遍历一遍,主要思想还是循环。请看下面代码。
void list(node temphead){
	while(temphead!=NULL)
	{
		printf("%d %lf\n",temphead->iNum,temphead->score);
	    temphead=temphead->pNodeNext;//更新指针,直到为空指针就代表遍历完所有的结构 
	}
}
同时我们要想查找一个学生的成绩,或者知道成绩查序号,我们就需要一个函数能够找出这样的结构并且输出它。这个也比较容易实现,主要思想还是在遍历链表的时候进行比较。
node search(node temphead,double score)
{
	while(temphead!=NULL)
	{
		if(temphead->score==score)
		   return temphead;
		else
		   temphead=temphead->pNodeNext;
	}
	return NULL;
 }
接下来就是链表最具特色的简单的插入函数了,这种插入操作简便,代码也很简洁且易懂。
void insert(node head,int i,node p)
{
	node temphead=head;
	int j;
	for(j=1;j<i;j++)
	    temphead=temphead->pNodeNext;
	node p2=temphead->pNodeNext;
	temphead->pNodeNext=p;
	p->pNodeNext=p2;
 } 
p需要在主函数中定义一下,这个插入函数是在第i个结构后面插入。不仅插入很简单,删除更是方便。

 void deletenode(node head,int i){//注意delete是关键字,别把它作为函数名
    int j;
    node temphead=head;
	node temphead2;
 	for(j=2;j<i;j++)
 	   temphead=temphead->pNodeNext;
 	temphead2=temphead->pNodeNext;
 	temphead2=temphead2->pNodeNext;
 	temphead->pNodeNext=temphead2;//通过直接修改被删结构的前一个结构的pNodeNext直接跳过了被删结构达到删除的目的 
 } 

这样就可以删除第i个链表结构了。对于链表的基本操作就是这些函数,纵观它们,其实我们并不是被复杂的逻辑而吓到(因为没有特别复杂的逻辑),而是被具体实现的过程中的各种变量名和类型名吓到了,其实把它们当做int等基本类型也未尝不可。一个指针指向什么类型就声明什么类型。对于链表,相信你在看完本篇文章后有了更深的体会,也希望你在接下来的学习中越学越好。最后也请多多关注我的博客,会有更多内容与大家分享,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值