大一下数据结构编程实验——线性结构及其应用

结束了大一上C语言的学习,脱离了被学生成绩管理系统支配的恐惧,开始来学习 万恶的 数据结构。

依稀记得当时为了做这个实验,我早早地吃完晚饭,守在电脑前,打开了 CodeBlocks、百度搜索(懂的都懂!!! )、QQ和微信(哈哈,信我,真的只是为了与外界取得联系!!! ),面前还摆着C语言课本和数结构课本, 真的是正襟危坐,紧张刺激。

这里说明一下,去年因为疫情的影响,全部在家上网课,而且数据结构实验课是在晚上。

等等,晚上?这不是变相让我们决战到天亮吗???

果然,老师诚不负我。曾天真地以为可以永远告别学生成绩管理系统了,好家伙,它又给我回来了!!!(原地死亡

大一下数据结构编程实验——线性结构及其应用_第1张图片

实验要求如下:
学期结束,辅导员需要收集两个班级的同学的C语言课程成绩。请你为辅导员做一个成绩录入统计,帮助辅导员更好地工作。(请问你分钱给我吗?没有凭什么将你的快乐建立在我的痛苦之上?

大一下数据结构编程实验——线性结构及其应用_第2张图片

(1)成绩信息录入——线性表的建立与遍历
操作1:初始化空表
操作2:按成绩降序插入所有同学的学号、班级信息和成绩到各自班级链表
操作3:查找/删除,若对应班级链表中无该同学信息,则输出无法找到
操作4:信息输出,线性表的遍历
(2)信息汇总
信息统计:将同学们的成绩合并到总表
(3)建表翻转
将总表中信息翻转到新表中

算了,还是写吧。
但请你记住,我不是在帮你,我只是想改变世界!!!

大一下数据结构编程实验——线性结构及其应用_第3张图片

下面奉上鄙人的拙劣的代码:

#include 
#include 

//定义学生信息节点
typedef struct node{
     
    int ID_num;  //学号
    int Class_num;  //班级
    int C_score;  //分数
    struct node *next;
}STUDENTNODE;

//建立学生信息节点,返回指向该节点的指针
STUDENTNODE* StudentListNodeCreat(int Class_num, int ID_num, int C_score){
     
    STUDENTNODE *p;
    p = (STUDENTNODE *)malloc(sizeof(STUDENTNODE));   //给新建节点分配存储空间
    if(!p)  exit(0);
    p->ID_num = ID_num;
    p->Class_num = Class_num;
    p->C_score = C_score;
    p->next = NULL;  //指针初始化为NULL
    return p;
}

//在已有的成绩降序链表中插入新建学生信息节点,并保持链表成绩仍为降序
STUDENTNODE* Insert_Descending(STUDENTNODE *head, STUDENTNODE *node){
     
    STUDENTNODE *p, *q;
    p = head;
    q = node;
    while(p->next){
       //链表下一节点存在
        if((p->next->C_score) > q->C_score){
       //若下一节点的成绩大于插入节点的成绩
            p = p->next;  //继续向下搜索
        }
        else{
     
            q->next = p->next;  //若下一节点的成绩小于或等于插入节点的成绩
            p->next = q;
            break;
        }
    }
    if(!(p->next)){
     
        q->next = p->next;  //搜索至链表末端时,将节点插入末端
        p->next = q;
    }
    return head;
}

//根据学号搜索学生信息,若有,则输出成绩,若没有,输出没有该学生信息
void SearchByID_num(STUDENTNODE *head, int ID_num){
     
    STUDENTNODE *p;
    p = head;
    while(p->next){
       //下一节点存在
        if((p->next->ID_num) != ID_num){
       //若下一节点的学号不等于搜索的学号
            p = p->next;  //继续向下搜索
        }
        else{
     
            printf("It is    { Class_number: %d, ID_number: %d, C_score: %3d }\n", p->next->Class_num, p->next->ID_num, p->next->C_score);  //匹配到相应学号时
            break;
        }
    }
    if(!(p->next)){
     
       printf("This class has no such student as ID_number = %d\n", ID_num);  //搜索至链表末端时,返回没有相应学生信息
    }
}

//根据学号删除学生相关信息
STUDENTNODE* DeleteByID_num(STUDENTNODE *head, int ID_num){
     
    STUDENTNODE *p, *q;
    p = head;
    while(p->next){
       //下一节点存在
        if((p->next->ID_num) != ID_num){
       //若下一节点的学号不等于搜索的学号
            p = p->next;  //继续向下搜索
        }
        else{
     
            q = p->next;  //匹配到相应学号时
            p->next = q->next;  //将p的指针指向下一节点存放的指针所指向的地址
            free(q);  //释放内存
            printf("Success!\n");
            break;
        }
    }
    if(!(p->next)){
     
       printf("This class has no such student as ID_number = %d\n", ID_num);  //搜索至链表末端时,返回没有相应学生信息
    }
    return head;
}


//复制参数节点
STUDENTNODE* NodeCopy(STUDENTNODE *node){
     
    STUDENTNODE *newnode;
    newnode = (STUDENTNODE *)malloc(sizeof(STUDENTNODE));  //为新节点分配空间复制各部分的值,指针初始化为NULL
    newnode->Class_num = node->Class_num;  //复制各部分的值指针初始化为NULL
    newnode->ID_num = node->ID_num;
    newnode->C_score = node->C_score;
    newnode->next = NULL;  //指针初始化为NULL
    return newnode;
}

//将两个班级的成绩表合并为一个新的总表,表中成绩仍按降序处理,同时不破坏原有分表
STUDENTNODE* MergeStudentList(STUDENTNODE* heads[], STUDENTNODE *MergeList){
       //参数为待合并分表和合并总表头结点的指针
    STUDENTNODE *p, *q, *r, *copynode;
    p = heads[0]->next;
    q = heads[1]->next;
    r = MergeList;
    while(p && q){
       //当两个指针指向的节点同时存在时,比较两节点的成绩
        if((p->C_score) >= (q->C_score)){
       //p指针指向节点的成绩大于或等于q指针指向节点的成绩
            copynode = NodeCopy(p);  //复制p指针指向的节点,该节点为满足条件的待插入节点
            r->next = copynode;
            r = r->next;
            p = p->next;
        }
        else{
     
            copynode = NodeCopy(q);  //复制q指针指向的节点,该节点为满足条件的待插入节点
            r->next = copynode;
            r = r->next;
            q = q->next;
        }
    }
    while(p){
       //当p指针指向节点存在,即分表还未遍历时,依次插入所有节点
        copynode = NodeCopy(p);
        r->next = copynode;
        r = r->next;
        p = p->next;
    }
    while(q){
       //当q指针指向节点存在,即分表还未遍历时,依次插入所有节点
        copynode = NodeCopy(q);
        r->next = copynode;
        r = r->next;
        q = q->next;
    }
    return MergeList;
}

//将总表逆序排列,即表中成绩按升序处理,同时不破坏原有总表
STUDENTNODE* ReverseStudentList(STUDENTNODE *MergeList,STUDENTNODE *ReverseList){
       //参数为待逆序总表和逆序总表头结点的指针
    STUDENTNODE *p, *q, *newnode;
    p = MergeList->next;
    q = ReverseList;
    while(p){
       //依次遍历并复制每一个节点,不断将复制形成的节点插入到头结点与第一个节点之间,最终达到逆序的效果
        newnode = NodeCopy(p);  //复制当前节点
        newnode->next = q->next;  //将复制形成的节点插入头结点与第一个节点之间
        q->next = newnode;
        p = p->next;
    }
    return ReverseList;
}

//打印单个学生节点信息
void PrintStudentNode(STUDENTNODE *node){
     
    STUDENTNODE *p;
    p = node;
    printf("{ Class_number: %d, ID_number: %d, C_score: %3d}\n", p->Class_num, p->ID_num, p->C_score);
}

//打印整个学生信息表
void PrintStudentList(STUDENTNODE *head){
     
    STUDENTNODE *p;
    p = head->next;
    while(p){
     
        printf("{ Class_number: %d, ID_number: %d, C_score: %3d }", p->Class_num, p->ID_num, p->C_score);
        p = p->next;
        if(p){
     
            printf("->\n");  //存在后继节点,则以"->"来表示
        }
    }
    printf("\nThat's all\n");
}

int main()
{
     
    int n_student;  //学生个数
    char order;      //用户选择
    int tempClass;
    int tempID;
    int tempScore;
    STUDENTNODE* tempNode;
    STUDENTNODE* MergeList;  //降序总表头指针
    STUDENTNODE* ReverseList;  //升序总表头指针
    STUDENTNODE* Class[2] = {
     StudentListNodeCreat(0,0,0),StudentListNodeCreat(1,0,0)};  //为两个班级分表创建头结点
    printf("\n                  ################################################################                  \n");
    printf("1.Insert_Descending  2.Search by ID_number  3.Delete by ID_number  4.Merge  5.Reverse  6.Print  q.Quit\n");
    printf("\n                  ################################################################                  \n");
    printf("Input your order:    ");
    while(scanf(" %c", &order)){
       //检查是否读取到有效值
        switch (order){
       //查看用户指令
        case '1':
            printf("How many student do you want to input?    ");
            while(getchar() != '\n'){
       //清除缓冲区中的所有字符
                continue;
            }
            while(scanf("%d", &n_student)){
       //检查是否读取到有效值
            while(n_student != 0){
     
                printf("Input the data format as Class_number,ID_number,C_score:    ");
                while(getchar() != '\n'){
       //清除缓冲区中的所有字符
                    continue;
                }
                while((scanf("%d,%d,%d", &tempClass, &tempID, &tempScore) != 3)){
       //检查是否读取到有效值
                    while(getchar() != '\n'){
       //清除缓冲区中的所有字符
                    continue;
                    }
                    printf("Error!Please input again!\n");  //提示错误并要求重新输入
                    printf("Input the data format as Class_number,ID_number,C_score:    ");
                }
                tempNode = StudentListNodeCreat(tempClass, tempID, tempScore);  //新建学生信息节点
                Class[tempClass] = Insert_Descending(Class[tempClass], tempNode);  //将新建节点按降序插入班级表中
                printf("This is the node you have inserted:    ");
                PrintStudentNode(tempNode);  //输出插入的学生节点信息
                n_student--;
            }
            break;
        case '2':
            printf("Input the data format as:Class_number,ID_number:    ");
            while((scanf("%d,%d", &tempClass, &tempID) != 2)){
       //检查是否读取到有效值
                    while(getchar() != '\n'){
       //清除缓冲区中的所有字符
                    continue;
                    }
                    printf("Error!Please input again!\n");  //提示错误并要求重新输入
                    printf("Input the data format as:Class_number,ID_number:    ");
                }
            SearchByID_num(Class[tempClass], tempID);
            break;
        case '3':
            printf("Input the data format as:Class_number,ID_number:    ");
            while((scanf("%d,%d", &tempClass, &tempID) != 2)){
       //检查是否读取到有效值
                    while(getchar() != '\n'){
       //清除缓冲区中的所有字符
                    continue;
                    }
                    printf("Error!Please input again!\n");  //提示错误并要求重新输入
                    printf("Input the data format as:Class_number,ID_number:    ");
                }
            Class[tempClass] = DeleteByID_num(Class[tempClass], tempID);
            break;
        case '4':
            MergeList = StudentListNodeCreat(-1,0,0);  //为降序总表创建一个头结点
            MergeList = MergeStudentList(Class,MergeList);
            printf("The list merged:\n");
            PrintStudentList(MergeList);
            break;
        case '5':
            ReverseList = StudentListNodeCreat(-1,0,0);  //为升序总表创建一个头结点
            ReverseList = ReverseStudentList(MergeList,ReverseList);
            printf("The list reversed:\n");
            PrintStudentList(ReverseList);
            break;
        case '6':
            printf("\nClass 0:\n");
            PrintStudentList(Class[0]);
            printf("\n");
            printf("\nClass 1:\n");
            PrintStudentList(Class[1]);
            break;
        case 'q':
            exit(0);
        default:
            printf("Error!Please input again!\n");  //若用户输入选项以外的其他字符,提示输入错误并要求重新输入
            break;
        }
        printf("\n                  ################################################################                  \n");
        printf("1.Insert_Descending  2.Search by ID_number  3.Delete by ID_number  4.Merge  5.Reverse  6.Print  q.Quit\n");
        printf("\n                  ################################################################                  \n");
        printf("Input your order:    ");
        }
    }
    return 0;
}

欸,我不就闭关了一会,怎么大家都睡了啊???
大一下数据结构编程实验——线性结构及其应用_第4张图片

除了满足基本要求外,鄙人还作贱自己添加了几个小小的功能:
1、程序只会读取输入的第一个字符作为指令,且程序在读到除以上字符外的其他字符时,都会提示用户重新输入,直至输入正确指令。
2、程序在读取输入时会通过scanf函数的返回值判断输入是否达到要求,若返回值错误,则会提示用户重新输入,直至输入格式完全正确,来提高程序的健壮性。
3、程序在每次读取输入之后都会清空缓冲区中的字符,避免存留字符对下一次的读取造成严重影响,可进一步防止程序崩溃。
4、在合并总表及翻转总表时,采用复制节点的方式,保证原表节点的信息不变,因此在合并或翻转后打印原表,也不会出现存放数据错误的现象。
5、在插入节点之后都会输出插入的节点信息,便于用户纠错并删除错误节点。

大一下数据结构编程实验——线性结构及其应用_第5张图片
敲黑板!!!数据结构非常非常非常地难,请反复反复反复练习。(自己都做不到凭什么说别人。。。

大一下数据结构编程实验——线性结构及其应用_第6张图片

你可能感兴趣的:(数据结构,数据结构,算法,c语言,链表)