在设计动态链表用于存放学生的姓名,学号和三门课程的成绩,要求设计del函数实现对前六个学生中成绩平均分最高与最低的学生数据删除。
在设计过程中遇到了下列问题
1.动态链表的输出多了一段地址
2.结构体指针在使用时发生了冲突。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define len sizeof(struct date)
int n;//节点数量
struct date//建立结构体
{
char name;//姓名
int id;//学号
int score1;//成绩1
int score2;//成绩2
int score3;//成绩3
struct date *next;//指向下一个结构体的指针
};
struct date* creat(void)//创建动态链表并返回头指针
{
struct date* head, * p1, * end;
n = 0;
p1 = end = (struct date*)malloc(len);
printf("请输入学生的姓名,学号,以及三门课程的成绩:\n");
scanf("%c,%d %d %d %d", &p1->name,&p1->id, &p1->score1, &p1->score2, &p1->score3);
head = NULL;
while (p1->name!=32)
{
n = n + 1;
if (n == 1)
head = p1;
else
end->next= p1;
end = p1;
p1 = (struct date*)malloc(len);
scanf("%c,%d %d %d %d", &p1->name, &p1->id, &p1->score1, &p1->score2, &p1->score3);
}
end->next = NULL;//尾指针
return(head);
}
struct date* creat(void);
void del(struct date* pt);
int main()
{
int i;
struct date* pt,;
pt = creat();//让pt成为头指针
printf("若不执行任何操作请输0\n");
printf("若要新增数据请输1;\n");
printf("若要删除前面6个学生中平均分最高和最低的学生的数据请输2\n");
scanf("%d", &i);
switch (i)
{
case 0:break;
//case 1:insert(pt, n); break;
case 2:del(pt); break;
}
do{
printf("%c,%d %d %d %d\n",(pt->name),(pt->id),(pt->score1),(pt->score2),(pt->score3));//输出链表
pt=pt->next;
} while (pt ->next!= NULL);
return 0;
}
void del(struct date* pt)//找出前6组数据中的最高,最低平均分并删去
{
struct date* h1 = pt,*h2=pt,*in=pt,*h3=pt;
int averge[6] = { 0 }, x = 0, i = 0, z = 0;
int y, o=0, p;
float min,max;
min = (float)(averge[0]);
max = (float)(averge[0]);
for (y= 0; y < 6; y++)
{
averge[y] = (float)((h2->score1 + h2->score2 + h2->score3) / 3);//用一个数组记录每个人的平均分
h2 = h2->next;
}
free(h2);
for (y = 0; y < 6; y++)
{
if ((float)averge[y] < min)
{
min = (float)averge[y];
o= y;//记下最小值的坐标
}
if ((float)averge[y] > max)
{
max = (float)averge[y];
p = y;
}
}
while (i < o && h1 != NULL)
{
in = h1;
h1 = h1->next;//使指针移动到要找到的坐标
i++;
}
if (h1 != NULL)
{
in->next = h1->next;//更改最小值坐标的前一个结构体的指针使其跳过该坐标
free(h1);
}
while (z < p && h3 != NULL)
{
in = h3;
h3= h3->next;
i++;
}
if (h3 != NULL)
{
in->next = h3->next;
free(h3);
}
}
思路:对于del函数,先用数组储存每个同学的平均分,然后再找出最高分与最低分的地址。对其前一个结构体的指针进行修改。
动态链表之所以会多出一段地址。是因为你的scanf里面有输入字符类型的变量,你每次输入一组数据是不是还要按一下回车。比如你输入a 1 2 3 4,此时输入缓冲区包含了a 1 2 3 4其实还有一个回车字符。程序在创建a 1 2 3 4这一个节点后再一次来到scanf函数,此时scanf发现缓冲区还有一个回车字符就不会让用户进行输入操作,而是会将回车也当作一个字符赋值给节点的name变量中,这就导致你输入一次数据程序实际上创建了两个节点。而回车这个字符是没有形状的,这也就是为什么你多出来的数据第一个字符显示空,后面四个int都是随机值。解决方法就是在scanf后面加一个getchar函数将回车字符回收掉。
代码仅供参考
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct stu {
char name;
int id;
int scoreOne;
int scoreTwo;
int scoreThree;
struct stu* next;
} STUDATE;
STUDATE* CreateDate(void);
STUDATE* DeleteMaxOrMin(STUDATE* headPtr_);
STUDATE* DeleteNode(STUDATE* headPtr_, STUDATE* nodePtr_);
void PrintList(STUDATE* headPtr_);
int main(void) {
STUDATE* headStr = CreateDate();
headStr = DeleteMaxOrMin(headStr);
PrintList(headStr);
return 0;
}
STUDATE* CreateDate(void) {
STUDATE* headPtr = NULL;
STUDATE* tempPtr = NULL;
STUDATE* endPtr = NULL;
while (1) {
tempPtr = (STUDATE*)malloc(sizeof(STUDATE));
tempPtr->next = NULL;
scanf("%c%d%d%d%d", &(tempPtr->name), &(tempPtr->id), &(tempPtr->scoreOne), &(tempPtr->scoreTwo), &(tempPtr->scoreThree));
getchar();
if (tempPtr->name == '#')
break;
if (headPtr == NULL) {
headPtr = tempPtr;
endPtr = tempPtr;
} else {
endPtr->next = tempPtr;
tempPtr->next = NULL;
endPtr = tempPtr;
}
}
return headPtr;
}
STUDATE* DeleteMaxOrMin(STUDATE* headPtr_) {
STUDATE* maxPtr = headPtr_;
STUDATE* minPtr = headPtr_;
int avergeMin = 0;
int avergeMax = 0;
int currentAverge = 0;
STUDATE* ptr = headPtr_->next;
while (ptr) { // ptr != NULL
avergeMax =
(maxPtr->scoreOne + maxPtr->scoreTwo + maxPtr->scoreThree) / 3;
avergeMin =
(minPtr->scoreOne + minPtr->scoreTwo + minPtr->scoreThree) / 3;
currentAverge = (ptr->scoreOne + ptr->scoreTwo + ptr->scoreThree) / 3;
if (currentAverge < avergeMin)
minPtr = ptr;
if (currentAverge > avergeMax)
maxPtr = ptr;
ptr = ptr->next;
}
// delete
if (maxPtr == minPtr) // 代表所有学生平均成绩都相等 不做删除操作
return headPtr_;
headPtr_ = DeleteNode(headPtr_, maxPtr);
headPtr_ = DeleteNode(headPtr_, minPtr);
return headPtr_;
}
STUDATE* DeleteNode(STUDATE* headPtr_, STUDATE* nodePtr_) {
STUDATE* deletePrev = headPtr_;
if (nodePtr_ == headPtr_) {
headPtr_ = headPtr_->next;
nodePtr_->next = NULL;
free(nodePtr_);
return headPtr_;
}
while (deletePrev->next != nodePtr_) // 指向删除节点的前一个节点
deletePrev = deletePrev->next;
if (nodePtr_->next = NULL) { // 要删除的在最后
deletePrev->next = NULL;
free(nodePtr_);
} else { // 在中间
deletePrev->next = nodePtr_->next;
nodePtr_->next = NULL;
free(nodePtr_);
}
return headPtr_;
}
void PrintList(STUDATE* headPtr_) {
STUDATE* str = headPtr_;
while (str) {
printf("%c %d %d %d %d\n", str->name, str->id, str->scoreOne, str->scoreTwo, str->scoreThree);
str = str->next;
}
}
```c
```
修改完善如下,供参考:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define len sizeof(struct date)
int n;//节点数量
struct date//建立结构体
{
char name;//姓名
int id;//学号
int score1;//成绩1
int score2;//成绩2
int score3;//成绩3
struct date *next;//指向下一个结构体的指针
};
struct date* creat(struct date *head);
void del(struct date** pt);
struct date* creat(struct date *head)//创建动态链表并返回头指针
{
struct date* p1, * end;
while (1)
{
p1 = (struct date*)malloc(len);
p1->next = NULL;
scanf(" %c", &p1->name);
if (p1->name == '#') { //以 '#' 结束输入
free(p1);
break;
}
scanf("%d %d %d %d",&p1->id, &p1->score1, &p1->score2, &p1->score3);
if (head == NULL)
head = p1;
else{
for (end = head;end->next; end=end->next);
end->next= p1;
}
}
return(head);
}
int main()
{
int i;
struct date* pt=NULL;
pt = creat(pt);//让pt成为头指针
printf("删除前面6个学生中平均分最高和最低的学生的数据:\n");
del(&pt);
do{
printf("%c %d %d %d %d\n",(pt->name),(pt->id),(pt->score1),(pt->score2),(pt->score3));//输出链表
pt=pt->next;
} while (pt != NULL);
return 0;
}
void del(struct date** pt)//找出前6组数据中的最高,最低平均分并删去
{
struct date* h1 = (*pt),*h2=(*pt),*in=NULL;
int y, i=0;
float average,min,max;
for (y = 0;h2 && y < 6; y++)
{
average = ((h2->score1 + h2->score2 + h2->score3) / 3.0);
if (y == 0){
min = max = average;
}
else{
if (average < min)
min = average;
if (average > max)
max = average;
}
h2 = h2->next;
}
while (h1 != NULL && i < y)
{
average = ((h1->score1 + h1->score2 + h1->score3) / 3.0);
if (min == average || max == average){
if (in == NULL){
in = (*pt);
(*pt) = in->next;
free(in);
in = NULL;
h1 = (*pt);
}
else{
in->next = h1->next;
free(h1);
h1 = in->next;
}
}
else{
in = h1;
h1 = h1->next;
}
i++;
}
}
运行效果: