单链表中头结点的有无。Ps:并讨论有无头结点在单链表的创建,打印,插入,逆置,删除中的区别

我开始做链表这块的时候也很纳闷,但是有了麻烦就得解决,不然会一直影响你以后的学习.      那我们现在就具体的讨论一下“有无头结点在单链表的创建,打印,插入,合并排序,逆置,删除中的区别”.

1.先根据下面这两张图来区分有无头结点的异样:

(1)不带头结点的单链表.

2)带头结点的单链表.

我也是个小白,图做的可能不是很一目了然,一下就看清楚,但是大家别把头结点的有无想的那么神秘.

简单的说头指针仅仅是存储单链表正式开始的首结点的指针值,有了它才能正常的访问整个链表的任意结点数据,但在程序中并没有给它分配动态空间,所以也就不存在头指针的域值.

而头结点就是我第二张图中说的那样在链表的首结点之前动态分配的一个结点.  头结点的作用我有转载一篇别人的文章,可以看看,可以帮你更好的理解.

 

2:单链表的创建

现在我拿代码来说.

 

struct Student *creat(void)
{ 
	struct Student *head;         //定义头结点 
	struct Student *p1,*p2;
	head=(struct Student *)malloc(LEN);            //让头指针指向头结点.   
	p1=p2=(struct Student *)malloc(LEN);          // 创建首结点,结构体指针变量p1,p2都指向首结点. 
	printf("请输入学生的学号和成绩: \n");
	scanf("%ld%f",&p1->num,&p1->score);
	n=0;
	head->next=NULL;                   //不带头结点的则为:head=NULL;		
	while(p1->num!=0)
	{
		n=n+1;
		if(n==1) head->next=p1;	       //不带头结点的则为:head=p1;
		else p2->next=p1;
		p2=p1;
		p1=(struct Student *)malloc(LEN);
		scanf("%ld%f",&p1->num,&p1->score);	
	}
	p2->next=NULL;
	free(p1);	        //释放开辟的新节点,因为此时该结点不会再链入单链表. 
	return(head);
}

3.单链表的结点数据打印

 

void print(struct Student *head)
{
	struct Student *p;
	p=head->next;          	//这里的P指针实际指向的是首结点.若是不带头结点的链表,此处应为:p=head.
	printf("\nNow,These %d records are :\n",n);    
	if(head->next!=NULL)         	// 若不带头结点,此处应为:p=head.
    {
		do
		{
			printf("\t%5ld %5.1f\n",p->num,p->score);
			p=p->next;
		}while(p!=NULL);
}

4.单链表的前插法:

 

 struct Student *Insert1(struct Student *head) //利用前插法插入一个数据。 
{
	struct Student *p;
	p=(struct Student *)malloc(LEN);
	scanf("%ld%f",&p1->num,&p1->score);
	p->next=head->next; 
	head->next=p;
	n++;         //链表结点增加. 
	return(head);
}
这是前插的示意图:
 
 

(1) 首先把 head->next赋值给p->next(data_new->next),这个时候新结点的next指针指向data 1

(2) 把 p (data_new)赋值给 head->next,完成前插.联系上图很好理解的.
 
5:单链表的后插法:

 

struct Student *Insert2(struct Student *head) //利用后插法插入一个数据。 
{
	struct Student *p1,*p=head->next;
	while(p&&p->next!=NULL)  p=p->next;
	p1=(struct Student *)malloc(LEN);
	scanf("%ld%f",&p1->num,&p1->score);
	p->next=p1;
	p1->next=NULL;
	n++;		  //链表结点增加. 
	return(head);
}
后插法示意图:

 

 

(1)首先通过循环找到尾结点,然后把 p(data_new) 赋值给p1->next,原来的尾结点的NEXT指针不再
为NULL,而是存放新节点的指针值,并指向新节点.
(2)执行代码p1->next =NULL,(即data_new->next = NULL) ,让新结点的指针域为空,完成插入.
 
6.单链表中的某位置插入新结点.
 
代码如下:
struct Student *Insert3(struct Student *head)
{
	char name[20];
	struct Student *pt;
	pt=(struct Student *)malloc(LEN);
	struct Student *p=head->next;
	printf("\n             ^_^ ,现在你输入一个学生的信息,我给你放在你想放的位置: ");
	scanf("%s%f",pt->name,&pt->num);
	printf("\n                那么你想放在谁的后面呢?:");
	scanf("%s",name);
	while(p&&(strcmp(p->name,name)!=0))  p=p->next;
	pt->next=p->next;
	p->next=pt;
	n++;
	
	return head;
}
该插入代码首先执行的是 输入一个学生的信息,然后根据提示输入,把数据放在的某人成绩单后面的位置
完成插入.
代码没有示意图,先卖个关子,大家可以自己画一下图...
 
7:单链表的删除。
 
首先我发现好多的代码都是根据结点数据值 num来删除结点,这样的好处是num值大多是按照结点顺序来排列的
,能很好地理解,那我们不妨换个思路,根据某个结点的某个数据来删除结点,这样的话对单链表的删除才能有
更好的加深理解.先来看代码:
struct Student *Delete(struct Student *head)
{
	char stu_name[20];
	struct Student *pTemp,*pPre;
	pTemp=pPre=head->next;
	printf("\n                亲,请输入你想要删掉的学生姓名: ");
	scanf("%s",stu_name);
	if(strcmp(stu_name,pTemp->name)==0) //如果输入的姓名和成绩单中的第一个学生姓名相同,就执行if语句. 
	{
		head->next=pTemp->next;   // 完成头结点和首结点之后的结点之间的连接. 
		free(pTemp);			//  释放当前结点. 
		return(head);
		n--;			//学生的人数减一. 
	}
	else                              //如果输入的姓名和成绩单中的第一个学生姓名不同,就执行else语句.
	{
		while(strcmp(pTemp->name,stu_name)!=0) //先根据循环找到当前要删除的结点,进而也找到了前一个结点. 
		{
			pPre=pTemp;
			pTemp=pTemp->next;
		}
		pPre->next=pTemp->next;  //连接前一个结点与当前要删除结点的下一个结点. 
		free(pTemp);            //释放当前结点,完成删除. 
		n--;					// 学生人数减一. 
		return(head);
	}
}
再看下示意图:

 

大家好好看一下,加深理解.
 
8:单链表的逆置.
 
代码如下:
struct Student *revers(struct Student *head)
{  
    struct Student *p1,*p2,*r;  
    p1 = head->next;  
    p2=r=NULL;  
    while(p1)  
    {  
        p2 = p1->next;  // 1 首先让P2指向当前结点的下一个结点. 
        p1->next = r;   // 2 然后让当前结点的指针域存放前一个结点的起始指针值. 
        r = p1;  		// 3 让 r 指向当前结点. 
        p1 = p2;        // 4 让当前的p1和p2指针值相同,指向下一个结点. 
    }  					// * 在没有指向尾结点之前, 循环以上四条代码
    return r;  			// * 每一次改变一次结点之间的指向,最后完成逆置 
} 
再看下示意图加深理解:
 

 

 
单链表的逆置核心部分:
        p2 = p1->next;  
        p1->next = r;  
        r = p1;  
        p1 = p2;
这四条语句在没有达到原链表的表尾之前一直循环执行,每一次执行都改变一次指向,最终达到逆置的效果.
 
 
以上就是我想分享给大家的,如果有什么地方不对,希望大家可以提出意见.
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值