数据结构单链表

#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函数,由于对时间复杂度进行了限制,要有一定的巧妙的思想
原文地址:https://www.cnblogs.com/wssblogs/p/7771745.html