• 数据结构单链表


    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    using namespace std;
    
    typedef struct XscjNode{
        char NO[10];
        char Name[16];
        char Mtel[11];
        char Email[16];
        char BornAddr[20];
        float AScore;
        float BScore;
        struct XscjNode *next;
    }XscjList,*XscjLink;
    
    void menu(){
        cout<<"                                                                                        "<<endl;
        cout<<"                                                                                        "<<endl;
        cout<<"                                                                                        "<<endl;
        cout<<"         |-----------------------------------------------------------------------------|"<<endl;
        cout<<"         |菜单目录。实现如下学生成绩管理的设计要求:                                    |"<<endl;
        cout<<"         |1.实现创建学生成绩链表函数 Build 。                                          |"<<endl;
        cout<<"         |2.实现函数Update,将姓名为Name的学生的A分成绩改为ScoreA。                    |"<<endl;
        cout<<"         |3.实现函数Insert,插入学号为NO,姓名为Name学生信息,将链表中学号≤NO的结点放   |"
      <<"
    "<<"         |到该结点的前面,将学号>NO的结点放到该结点后面。                              |"<<endl;
        cout<<"         |4.实现函数Sort,将该学生按照B分成绩进行非递减排序。                          |"<<endl;
        cout<<"         |5.实现函数Merge,将两个按B分成绩非递减排序的学生成绩单合并为一个按B分成绩非  |"
      <<"
    "<<"         |递增排序的通讯录,B分成绩相同且学号相同的成绩记录在结果中只保留一个。        |"<<endl;
        cout<<"         |6.实现函数Count;统计籍贯是“广州”的学生人数。                              |"<<endl;
        cout<<"         |7.实现函数MoveK,将学生的成绩链表中倒数第k个结点之后的所有结点移到头结点后面 |"
      <<"
    "<<"         |(保持结点间的先后顺序)。                                                     |"<<endl;
        cout<<"         |8.实现函数ReverseN,将学生成绩链表的正中间位置结点之后的全部结点倒置。       |"<<endl;
        cout<<"         |输入1-8实现相应要求,输入0结束。请输入:                                     |"<<endl;
        cout<<"         |-----------------------------------------------------------------------------|"<<endl;
    }
    
    void Build(XscjLink &T){ /** fread ?**/
    
        T=(XscjLink)malloc(sizeof(XscjList));
        T->next=NULL; //头结点
        XscjLink p;
        p=T; //遍历链表,向下传递
    
        char filename[20];
        FILE *fp;
        cout<<"创建一个学生成绩链表,学生数据以文件形式输入,输入文件名:"<<endl;
        cin>>filename;
        getchar();
    
        while((fp=fopen(filename,"r"))==NULL){
            cout<<"无法打开文件!重新输入文件名:"<<endl;
            cin>>filename;
            getchar();
        }
    
        while(feof(fp)==0){ //空txt 空链表
            p->next=(XscjLink)malloc(sizeof(XscjList));
            fscanf(fp,"%s %s %s %s %s %f %f",p->next->NO,p->next->Name,p->next->Mtel,p->next->Email,p->next->BornAddr,&p->next->AScore,&p->next->BScore);
            p=p->next; //&q->NO——>整个数组内存的首地址
        }
        fclose(fp);
        p->next=NULL;
    }
    
    void Update(XscjLink &T,char *Name,float ScoreA){
        XscjLink p;
        p=T->next;
        if(T->next==NULL){
            cout<<"学生信息链表为空,无法修改学生成绩!"<<endl;
            exit(1);
        }
        while(1){
            if(p==NULL){
                cout<<"未找到名为"<<Name<<"的同学!"<<endl;
                break;
            }
            else if(strcmp(p->Name,Name)==0){
                p->AScore=ScoreA;
                cout<<"学生A分成绩修改成绩成功!"<<endl;
                break;
            }
            else{
                p=p->next;
            }
        }
    }
    
    void OutPut(XscjLink T){
        XscjLink p;
        int num=1;
        p=T->next;
        if(p==NULL){
            cout<<"学生信息链表为空,无数据输出!"<<endl;
            exit(1);
        }
        while(1){
            if(p==NULL){
                cout<<"学生信息输出完毕!"<<endl;
                break;
            }
            else{
                printf("第%d名学生信息:
    ",num);
                printf("学号为%s ;",p->NO);
                printf("姓名为%s ;",p->Name);
                printf("手机号为%s ;",p->Mtel);
                printf("邮箱地址为%s ;",p->Email);
                printf("籍贯为%s ;",p->BornAddr);
                printf("A分成绩为%.2f分,",p->AScore);
                printf("B分成绩为%.2f分。
    ",p->BScore);
                p=p->next;
                num++;
            }
        }
    }
    
    void Insert(XscjLink &T,char *Name,char *NO){
        XscjLink p,q,pfront;
        p=T->next;
        pfront=T;
        q=(XscjLink)malloc(sizeof(XscjList));
        strcpy(q->NO,NO);
        strcpy(q->Name,Name);
        strcpy(q->BornAddr,"未知");
        strcpy(q->Email,"未知");
        strcpy(q->Mtel,"未知");
        q->AScore=q->BScore=0;
        while(p->next!=NULL){
            if(strcmp(p->NO,NO)<=0){
                p=p->next;
                pfront=pfront->next;
            }
            else{
               break;
            }
        }
        //跳出循环情况有两种:尾结点;中间有大于NO的结点
        if(p->next==NULL){//p指向尾结点,但未经过比较
            if(strcmp(p->NO,NO)<0){
                p->next=q;
                q->next=NULL;
            }
            else /*(strcmp(p->NO,NO)>0)*/{
                pfront->next=q;
                q->next=p;
            }
        }
        else /*(strcmp(p->NO,NO)>0)*/{
            pfront->next=q;
            q->next=p;
        }
        cout<<"学生信息插入完毕!"<<endl;
    }
    
    int Count(XscjLink T,char BornAddr[20]){
        int num=0;
        XscjLink p;
        p=T->next;
        if(p==NULL){
            cout<<"学生信息链表为空,无法统计人数!"<<endl;
            exit(1);
        }
        while(p->next!=NULL){
            if(strcmp(p->BornAddr,BornAddr)==0){
                num++;
            }
            p=p->next;
        }
        if(strcmp(p->BornAddr,BornAddr)==0){
                num++;
            }
        return num;
    }
    
    void Sort(XscjLink &T){
        XscjLink p,pf,pb,sign,temp;//sign作为外层循环判断条件 temp存储中间变量 p为具体调换结点指针 pf、pb分别为p结点前后节点指针,便于交换
        p=T->next;
        pf=T;
        pb=p->next;
        sign=NULL;
        while(pb!=sign){
            while(pb!=sign){
                if(p->BScore>=pb->BScore){
                    //cout<<"进行一次交换"<<endl;
                    temp=pb->next;
                    pf->next=pb;
                    pb->next=p;
                    p->next=temp;
    
                    pf=pf->next;
                    pb=p->next;
                }
                else{
                    p=p->next;
                    pf=pf->next;
                    pb=p->next;
                }
            }
            sign=p;
            p=T->next;
            pf=T;
            pb=p->next;
        }
    
    }
    
    void Merge(XscjLink &T1,XscjLink &T2){
        Sort(T1);
        Sort(T2);
    
        XscjLink p1,p2,t,temp,p;
        t=T1;
        p1=T1->next;
        p2=T2->next;
    
        if(p1->BScore<p2->BScore){//先顶头结点后的第一个结点,并且指为next域为NULL
            temp=p1;
            p1=p1->next;
            t->next=temp;
            temp->next=NULL;
        }
        else if(p1->BScore<p2->BScore){//<、>时正常链接
            temp=p2;
            p2=p2->next;
            t->next=temp;
            temp->next=NULL;
        }
        else{//B分相等
            if(strcmp(p1->Name,p2->Name)==0){//是否为同一人
                temp=p1;
                p1=p1->next;
                t->next=temp;
                temp->next=NULL;
                p2=p2->next;
            }
            else{//不是同一人,B分成绩相等
                temp=p1;
                p1=p1->next;
                t->next=temp;
                temp->next=NULL;
            }
        }
    
        while(p1&&p2){ //链接T1、T2需要比较的结点  进行类似先前的第一个数结点的比较操作
            if(p1->BScore<p2->BScore){
                temp=p1;
                p1=p1->next;
                temp->next=T1->next;
                T1->next=temp;
            }
            else if(p1->BScore>p2->BScore){
                temp=p2;
                p2=p2->next;
                temp->next=T1->next;
                T1->next=temp;
            }
            else{
                if(strcmp(p1->Name,p2->Name)==0){
                    temp=p1;
                    p1=p1->next;
                    temp->next=T1->next;
                    T1->next=temp;
                    p2=p2->next;
                }
                else{
                    temp=p1;
                    p1=p1->next;
                    temp->next=T1->next;
                    T1->next=temp;
                }
            }
        }
        p=p1==NULL?p2:p1; //链接剩下结点,找到那个指针先NULL,链接另一个的结点p=p->next 循环进行
        while(p){
            temp=p;
            p=p->next;
            temp->next=T1->next;
            T1->next=temp;
        }
    
    }
    
    void MoveK(XscjLink &T,int k){
        XscjLink p,q,pf,qf,temp;
        int cout=0;
        p=T->next;
        q=T->next;
        pf=T;
        qf=T;
        while(p!=NULL){
            cout++;
            if(cout>k){
                qf=qf->next;
                q=q->next;
            }
            p=p->next;
            pf=pf->next;
        }
        temp=T->next;
        T->next=q;
        pf->next=temp;
        qf->next=NULL;
    }
    
    void ReverseN(XscjLink &T){
        XscjLink pm,pl,pmf,plf,temp;
        pm=pl=T->next;
        pmf=plf=T;
        while(pl!=NULL){
            pm=pm->next;
            pmf=pmf->next;
            pl=pl->next->next;
            plf=plf->next->next;
        }
        temp=pm;
        pm=pm->next;
        pmf->next=temp;
        temp->next=NULL;
        while(pm!=NULL){
            temp=pm;
            pm=pm->next;
            temp->next=pmf->next;
            pmf->next=temp;
        }
    }
    
    
    int main(){
    
        int goal;
        menu();
        cin>>goal;
        getchar();
        while(goal!=1){
            cout<<"没有链表存在无法进行其他操作!重新输入:"<<endl;
            cin>>goal;
            getchar();
        }
        while(goal!=0)
            switch(goal){
                case 1:     cout<<"实现Build函数。"<<endl;
                            XscjLink T;
                            Build(T);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 2:     cout<<"实现Update函数,修改学生A分成绩。输入学生姓名和修改A分成绩:"<<endl;
                            char name[16];
                            float ScoreA;
                            cin>>name>>ScoreA;
                            getchar();
                            Update(T,name,ScoreA);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
    
                case 3:     cout<<"实现Insert函数,以学号NO插入某学生信息。输入要插入的信息即姓名和学号(空格分开):"<<endl;
                            char Name[16];
                            char NO[10];
                            cin>>Name>>NO;
                            getchar();
                            Insert(T,Name,NO);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 4:     cout<<"实现Sort函数,将学生信息链表以B分成绩进行非递减排序。"<<endl;
                            Sort(T);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 5:     cout<<"实现Merge函数,将两个按B分成绩非递减排序的学生成绩链表合并为按B分成绩非递增排序的链表。"<<endl;
                            cout<<"该操作需要建立另一个学生信息链表"<<endl;
                            XscjLink P;
                            Build(P);
                            OutPut(P);
                            cout<<"实现合并操作,归并至第一个链表"<<endl;
                            Merge(T,P);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 6:     cout<<"实现Count函数,统计某籍贯的学生总人数。输入要统计的籍贯:"<<endl;
                            char BornAddr[20];
                            cin>>BornAddr;
                            getchar();
                            cout<<"籍贯为"<<BornAddr<<"的总人数为"<<Count(T,BornAddr)<<"人!"<<endl;
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 7:     cout<<"实现MoveK函数,将学生成绩链表中倒数第k个结点之后的所有结点移到头结点后面(保持结点间的先后顺序)。输入k的值:"<<endl;
                            int k;
                            cin>>k;
                            getchar();
                            MoveK(T,k);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                case 8:     cout<<"实现ReverseN函数,将学生成绩链表的正中间位置结点之后的全部结点倒置。"<<endl;
                            ReverseN(T);
                            OutPut(T);
                            cout<<"回车继续......"<<endl;
                            getchar();
                            menu();
                            cin>>goal;
                            getchar();
                            break;
                default:break;
        }
        cout<<"实验操作结束!"<<endl;
    
        return 0;
    
    }


      1.运用了少量的C文件操作技术,注意理解
      2.大多函数操作较于简单,主要思想就是遍历单链表,其中有关结点交换连接的问题,注意指针操作确实对链表进行了影响
      3.对于MoveK和ReverseN函数,由于对时间复杂度进行了限制,要有一定的巧妙的思想
  • 相关阅读:
    Homework template (latex)
    Basic skill of searching
    国庆第三次集训: 2012 ACM-ICPC Asia Regional Contest Chengdu Site
    新学期随笔
    暑期集训感想
    暑期集训 DP 篇
    POJ 1195 Mobile Phones 二维树状数组
    51Nod1246 罐子和硬币,不能均分的题
    一维战舰,一道考区间的好题
    51NOD 1268 和为K的组合 搜索水题
  • 原文地址:https://www.cnblogs.com/wssblogs/p/7771745.html
Copyright © 2020-2023  润新知