单向基础链表的基本操作及思维分享

需要实现的链表要求:

***创建单向动态链表,并对它进行插入、删除和输出等操作。 包括以下任务
(1) 写一个函数 create,用来建立一个动态链表,各结点数据由键盘输入;
(2) 写一个函数 print,将 create 所创建的链表中的各结点数据依次输出;
(3) 写一个函数 delete,用来删除动态链表中一个指定的结点(由实参指定某一学号, 表示要删除该学生结点);
(4) 写一个函数 insert,用来向动态链表中插入一个结点;
(5) 设计函数时请注意其封装性,不要随意使用全局变量。应通过主程序先后调用这 些函数,以实现链表的创建、输出、删除和插入,在主程序中指定需要删除和插 入的结点。
(6) 支持删除多个结点(自行设置结束条件:譬如输入拟删除学生的学号为 0 或学 生已删光),支持插入多个结点(自行设置结束条件:譬如输入拟插入学生学号 为 0);

要求分析:

1.对于要求一:建立链表
需要的就是建立动态链表,建立的思路如下:
1)定义两个结构体类型的指针 student *p1, *p2;
2)用new在内存中开辟一个结构体变量的空间,将地址赋给p1;

p1 = new student;  

3)数据由终端输入,赋给新开辟的变量空间;

cin >> p1->num >> p1->score

4)若输入数据有效,则将该结点作为链表中的第一个结点,让头指针指向它,head = p1;
令p2 = p1,p1用于捕获下一个new结点。

p2->next=p1;   p2=p1;

5)将下一组数据赋给新开辟的变量空间。 p1 = new student;

cin >> p1->num >> p1->score

6)若输入的数据有效,则将两个结点连接起来,p2->next = p1 再令p2 = p1, p1继续捕获 下一个new结点,做5。若输入的数据无效,p2就是链表的尾,则p2->next = NULL。通过步骤5,6的重复进行动态链表的实现。

用图像表示动态链表的建立:
用图像表示动态链表的建立
用静态链表表示动态链表的建立过程:

student  *p1, *p2,  *head; head = NULL;  //三个指针初始化
 p1 = p2 = new student; 
 cin>>p1->num>>p1->score; 
 if (p1->num!=0) //赋值有效 
 head = p1;
 
p1 = new student;  //p1继续开辟新结点 
cin>>p1->num>>p1->score; 
if (p1->num!=0) //赋值有效 
{ p2->next=p1;   p2=p1;}//建立第一结点

p1 = new student;
 cin>>p1->num>>p1->score;
  if (p1->num!=0)
   { p2->next=p1;   p2=p1; }//建立第二结点

if (p1->num==0)  //新结点赋值无效 
p2->next=NULL; 
return (head);//最后结点

真正实现动态链表的建立:

student* create( )  //函数(创建链表),返回值为指针类型 
{  student  *head, *p1,*p2;
   head = NULL; 
   p1 = p2  = new student;
   cin>>p1->num>>p1->score;
   while (p1->num!=0)   //只要赋值正确,结点就不断加入到链表中 
    { 
	    cout<<"Next"<<endl;
	    n = n+1;     
        if (n==1)  head=p1;  //若新入结点为链表中的第一个结点,则让头指针指向它
        else   p2->next=p1;   //p2挂住新加入的结点
        p2 = p1;   //p2指向新加入的结点
        p1 = new student;  //p1继续开辟新结点
        cin>>p1->num>>p1->score; 
	} 
	  cout<<"Over"<<endl;
	  p2->next = NULL;  //若p1->num=0 ,链表不再生长 
	  return(head); 
	  	delete p1;
	    delete p2;
	    p1=NULL,p2=NULL; //释放动态空间
	  } 

2.对于要求二,输出链表:
链表的输出只要通过head指针就能导出整个链表,通过while循环来读取,直到读到尾结点。

void print(student* head)  //输出链表
	   {   cout<<"录入的信息有"<<endl;
	       student* p; 
	       p = head; 
	       while(p!=NULL) {  
	       cout <<"学号:"<<p->num << " " <<"成绩:"<< p->score << endl; 
		   p = p->next;  
	    }
	    delete p;
	    p=NULL;
		}

3.对于要求三,删除结点:
删除的思路如下:
1)首先定义两个结构体类型的指针:student *p1, *p2;
2)将需要删除结点的链表的表头赋给p1:p1 = head;
3)判断p1所指向的结点是否为想删除的结点a1:p1->num == D?
4)若p1->num!=D,p2 = p1; p1指向下一个结点p1 = p1->next;继续 判断下一个结点是否是想删除的结点。继续做3。
5)若p1->num == D,则p1当前指向的结点就是要删除的结点,将 p2的next指向p1指向的下一个结点:p2->next = p1->next;

思路图片展示:
在这里插入图片描述
在删除结点时,还会遇到三种特殊情况:
1、链表为空。
解决办法:返回空指针,并输出相应提示。
2、拟删除的结点为第一个结点。
解决办法:调整head,使其 指向链表中的第二个结点。
3、没有找到拟删除的结点。
解决办法:应返回相应提示信息。

删除代码实现如下:

student* deleted(student* head, int num) //函数(删除学号为num的学生结点) 
   {   student  *p1,*p2; 
       if (head==NULL) 
          { cout<<"list is null"<<endl;  return  NULL;} 
	   p1 = head;
       while (p1->num!=num&&p1->next!=NULL)  //p1指向的不是wanted结点,也不是链尾 
          { p2 = p1;  p1 = p1->next;  } 
       if(p1->num==num)  //若while循环结束时 p1->num==num
          { if (num==head->num)   head = p1->next; 
            else  p2->next=p1->next;
			n = n-1;  //记录链表中结点总个数 
	      } 
	   else  cout<<"Not  found"<<endl;  //若while循环结束时p1->next==NULL 
	   return  (head); 
	   	delete p1;
	    delete p2; 
		p1=NULL,p2=NULL;  
	} 

4.对于要求四,插入链表:
思路如下:
1)定义三个结构体指针变量student *p1,*p2,*p0;
其中,p0指向拟插入的结点,p1指向已有链表头部,p1 = head;
2)比较p1->num与p0->num,若p1->num < p0->num,
则:p2 = p1; p1 = p1->next; 继续向后比较。
3)若p1->num >= p0->num,则p0应插在p2与p1之间,
则:p2->next = p0 ; p0->next = p1; 插入操作结束
思路图片展示:
在这里插入图片描述
在插入链表时,还会遇到四类特殊情况:
1、若链表为空,则将拟插入结点作为链表中的唯一的结点:

head=p0; 

2)若拟插入结点最小,则插入结点成为头结点;

p0->next=head;  
head=p0;

3)若拟插入结点最大,则插入到链尾,成为最后一个结点。

p2->next=p0;
p0->next=NULL;

4)插入已有结点(即数据重复)则进行数据覆盖,储存新的数据。

else if (p0->num==p1->num) { 
		     p1->score=p0->score;
		     }

插入结点,实现代码:

student *insert(student *head, student *stud) //函数(插入一个结点) 
{   student *p0,*p1,*p2;
    p1=head;    p0=stud;
    if (head==NULL) 
       {  head=p0;  p0->next=NULL;   } //插入结点为链表中唯一结点 
    else 
       {  while((p0->num>p1->num)&&(p1->next!=NULL)) 
             {  p2=p1;  p1=p1->next;  }
          if (p0->num<p1->num) {  
            if (p1==head)    
	           {p0->next=head; head=p0; }  
	        else  {p2->next=p0;  p0->next=p1;}  //p0插入到p2和p1之间 
			} 
		  else if (p0->num==p1->num) { 
		     p1->score=p0->score;
		   }
	      else  {p1->next=p0;  p0->next=NULL;} //p0成为链表最后一个结点 
	   }   

**对于要求五和要求六,主要体现在思考整个思路时,应该设立的限定条件和代码整体优化上。在代码中应有清楚的提示信息,使用户交互体验好,这点也是非常重要的。 **
在本次实验中值得注意的有:
1)结束程序时自动执行链表撤销储存空间函数,delete 掉动态分配的空间。并让指针指向NULL,避免出现野指针。释放空间避免出错。
2)调用链表时,只需对head指针进行操作。
3)留意链表持续和结束的条件,避免让链表无限建立或者无限寻找出错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值