数据结构单链表

#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的结点放   |"
  <<"\n"<<"         |到该结点的前面,将学号>NO的结点放到该结点后面。                              |"<<endl;
    cout<<"         |4.实现函数Sort,将该学生按照B分成绩进行非递减排序。                          |"<<endl;
    cout<<"         |5.实现函数Merge,将两个按B分成绩非递减排序的学生成绩单合并为一个按B分成绩非  |"
  <<"\n"<<"         |递增排序的通讯录,B分成绩相同且学号相同的成绩记录在结果中只保留一个。        |"<<endl;
    cout<<"         |6.实现函数Count;统计籍贯是“广州”的学生人数。                              |"<<endl;
    cout<<"         |7.实现函数MoveK,将学生的成绩链表中倒数第k个结点之后的所有结点移到头结点后面 |"
  <<"\n"<<"         |(保持结点间的先后顺序)。                                                     |"<<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名学生信息:\n",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分。\n",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函数,由于对时间复杂度进行了限制,要有一定的巧妙的思想
时间: 2024-10-11 09:24:43

数据结构单链表的相关文章

python实现数据结构单链表

#python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" def __init__(self, elem): self.elem = elem self.next = None # 节点一开始初始化的时候并不知道下一个元素的地址,所以先设置为空 class SingLinkList(object): """单链表""

数据结构—单链表(类C语言描写叙述)

单链表 1.链接存储方法 链接方式存储的线性表简称为链表(Linked List). 链表的详细存储表示为: ① 用一组随意的存储单元来存放线性表的结点(这组存储单元既能够是连续的.也能够是不连续的) ② 链表中结点的逻辑次序和物理次序不一定同样.为了能正确表示结点间的逻辑关系,在存储每一个结点值的同一时候,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link)) 注意: 链式存储是最经常使用的存储方式之中的一个.它不仅可用来表示线性表.并且可用来表示各种非线性

C# 数据结构 - 单链表 双链表 环形链表

链表特点(单链表 双链表) 优点:插入和删除非常快.因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作. 缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了.(顺序表可以弥补这缺点,但插入和删除就非常耗性能) 单链表 单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针).最后一个节点的Next为null来标识链表的尾. 如下图 代码实现 1 /* ----

C# 数据结构--单链表

什么是单链表 这两天看到很多有关单链表的面试题,对单链表都不知道是啥的我.经过学习和整理来分享一下啥是单链表和单链表的一些基本使用方法.最后看些网上有关单链表的面试题代码实例. 啥是单链表? 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.这组存储单元既可以是连续的,也可以是不连续的. 链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据. 链表的结点结构

数据结构单链表实现

<数据结构>中单链表的实现c代码 转自:http://blog.chinaunix.net/uid-22750250-id-1769905.html include.h /******************************************************************      程序中要用的头文件******************************************************************/ #include<st

数据结构-单链表-类定义2-C++

上一次的C++链表实现两个单链表的连接不太理想,此次听了一些视频课,自己补了个尾插法,很好的实现了两个链表的连接,当然了,我也是刚接触,可能是C++的一些语法还不太清楚,不过硬是花了一些时间尽量在数据结构中将c++的语言特点表现出来.一开始也是不愿意读c++的数据结构,只是一种挑战心里,不想读着读着感觉自己太low了,c++的内容更加丰富,所以还得多多练习...... 头文件 1 #ifndef LIST_H 2 #define LIST_H 3 #include <iostream> 4 5

Java数据结构——单链表

一.单链表的概念 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.这组存储单元可以是连续的,也可以是不连续的. 存储单元由两部分组成,数据源和指针,数据源放数据,指针指向下个存储单元. 二.单链表的结构 采用Node实体类类标识,其中data为存储的数据,next为下一个结点的指针. //链表的实体类 class Node{ public int data; public Node next; public Node(int data) { this.data =

大话数据结构---单链表

单链表在存储结构上与顺序存储的区别:不用开辟连续的存储空间,存储位置任意,只需要让数据的前驱知道它的位置就可以,而使用单链表示只需要知道单链表的第一个元素就能找到其他所有的元素,为了方便 一般会设置一个头指针指向第一个元素. 单链表的数据读取:通过头指针一个一个往后遍历 单链表的插入: 删除: 自定义单链表的简单实现: package com.neuedu.entity; /* * 项目名称:JavaSqList * @author:wzc * @date 创建时间:2017年9月2日 上午9:

C实现通用数据结构--单链表

单链表概述 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 从概念上讲,可以把链表想象成一系列连续的元素,然而,由于这些元素是动态分配的(C语言中使用malloc),切记这些元素通常实际上都是分散在内存空间的 本文地址:http://www.cnblogs.com/archimedes/p/c-datastruct-linklist.html,转载请注明源地址. 单链表的接口定义: 1.list_init void list_init(Li

数据结构——单链表

1.对于一个有数据的单链表,如果要对其初始化,使用下列操作: 1 void initList(sqlist &L){ #对于需要改变的变量或链表,使用引用型 2 L.length==0; 3 } //单链表长度重置为0 2.单链表有4中操作:归并,插入,删除,查找 归并的实现:(链表A,B是有序的,且归并后的C也是有序的)如下: 1 void merge(LNode *A,LNode *B,LNode *&C){ //将A B两个链表归并为一个新的单链表(链表C采用引用型) 2 LNode