链表exp1

​​​​​​​ 编写一个链表结构,读取任意多个用户输入。之后将“2017000 85.0”和“2017006 85.0”“2017013 85.0”这三个数据插入链表,再将链表数据打印出来。以下给出程序框架,补充程序内容。

输入:

2017001 81.0
2017002 82.0
2017003 83.0
2017004 84.0
2017005 85.0
2017010 90.0
0 0

输出:

2017000  85.0
2017001  81.0
2017002  82.0
2017003  83.0
2017004  84.0
2017005  85.0
2017006  85.0
2017010  90.0
2017013  85.0
 

#define _CRT_SECURE_NO_WARNINGS
#include
#include/*malloc free等函数会使用到这头文件*/
/*定义链表的节点*/
typedef struct node_s{
	long num;//学号
	float score;//成绩
	struct node_s* next;//指向链表下一个节点的指针
}node_t;  /*node_t是typedef定义出来的节点类型*/
int n;  /*n用来统计链表的长度*/

/*创建一个包含学生信息的链表*/
node_t* create()
{
	//申请头指针,和两个操作用的指针p1 p2
    node_t *head, *p1, *p2;//p访问结构体内部成员
	
	//初始化数据
	n = 0;			//n用来统计链表的长度,初始化为0
	head = NULL;	//头指针初始化为NULL指针,链表为空
  
	//循环读取用户输入,直到读取到学号为0时,认为输入结束
    while (1)
	{
		//申请内存来创建节点,用p1指向新申请的节点
		//正常这里要判断一下p1是否为NULL,这里省略
        p1 = (node_t*) malloc(sizeof(node_t));
		
		//读取用户输入数据
        scanf("%ld %f", &p1->num, &p1->score);//输入一个num,和一个score数据,指针分别指向他们
		
		//如果读取到学号为0时,认为输入结束
		if(p1->num == 0)//p1指向数据num
			//本节点p1==0即尾节点,next设置为空指针
		{
			if(p2 != NULL)
            p2->next = NULL;
			//p1节点为0的无需使用,要释放内存,书上漏了
			free(p1);
			break;
		}

	//链表长度+1
		n++;
		if(n==1){
			//如果链表长度为1,说明当前节点p1是首节点
			//用head记录下当前首节点
			head = p1;
		}else {
			//如果链表长度不为1,说明当前节点p1不是首节点
			//用上一个节点P2的next记录下当前节点
            p2->next = p1;
			//把p2记为前趋,p1一直是新生成的节点
		}
		//p2记录下本轮的节点,用于下一轮有新节点是,在p2->next=p1;语句中使用
		p2 =p1;
	}

	//返回新生成的链表的首节点,用于外部访问链表
   return (head);
}
   //遍历链表,打印节点内容
   void print(node_t *head)
   {
	   node_t *p;
	   //如果链表为空,则不用访问了,直接返回
	   if(head == NULL){
		   return;
	   }
	   //p初始化为head指向的链表首元素
	   for(p = head;p!= NULL; p=p->next){
		   //如果p指向的不是空指针,则访问它的数据
		   printf("%ld %5.1f\n", p->num, p->score);}
		//访问完数据后,p要指向当前元素的下一个元素 p = p->next
    }

//遍历链表,将新节点stud插入到链表中的适当位置,保证链表的学号顺序从小到大;
node_t *insert(node_t *head, node_t *stud)
{
	node_t *p0,*p1,*p2;
	p1=head;//p1指向链表头节点,p2指向p1的上一结点
	p0=stud;//p0指向待插入的节点

	//part1、如果链表为空,则直接初始化链表,创建首结点
    if(head == NULL){
		head = p0;
		p0->next =NULL;
		n++;
		return head;
}
  //part2.以下while循环用于查找新节点适合的插入位置,插入到节点p1之前,P1的前一节点为p2
	//原理和node_t *del(node_t *head,int num)的part2相同
	p1 =head;//p1为头节点
	while(p1->next != NULL){ //p1的下一跳不为空时循环
		if(p0->num < p1->num){//??检查当前的p1的学号是否大于p0的学号,由于链表是从小到大排序的,第一个大于p0的学号节点,就是p0要插入的位置
			break;
		}else{
			p2=p1;//找不到,则用p2保存当前节点p1的地址
			p1=p1->next;//p1跳转到下一个节点,进行新一轮循环
		}
	}
	//part3.找不到合适的插入位置,加入队尾,此时p1指向的就是队尾的节点。
	if(p0->num > p1->num){
		p1->next =p0;
		p0->next = NULL;
		return head;
	}
	//part4.进行插入操作
	if(p1 ==head){  //插入位置时队首
		head = p0;//头指针指向新结点
		p0->next = p1;//新节点的后续指向原来的头节点

	}else{
		p2->next  =p0;//p1的上一节点,改为指向新节点
		p0->next  =p1;//新节点的后续指向原有的p1节点
	}
	n++;//链表长度+1
	//返回修改后链表头节点
	return head;
}
//输出
	
node_t* test_14_3(void)
{
    node_t* head;
    node_t* stud;

    head = create();

    //插入头部
    stud = (node_t*) malloc(sizeof(node_t));
    stud->num = 2017000;
    stud->score = 85.0;
    head = insert(head, stud);

    //插入中间
    stud = (node_t*) malloc(sizeof(node_t));
    stud->num = 2017006;
    stud->score = 85.0;
    head = insert(head, stud);

    //插入尾部
    stud = (node_t*) malloc(sizeof(node_t));
    stud->num = 2017013;
    stud->score = 85.0;
    head = insert(head, stud);

    print(head);

	return head;
}

int main(void)
{
    test_14_3();
}

 

你可能感兴趣的:(链表exp1)