day15

一、链表的引入


1.1    总结顺序表的优缺点


1>    优点:能够直接通过下标进行定位元素,访问效率高,对元素进行查找和修改比较快
2>    不足:插入和删除元素需要移动大量的元素,效率较低
3>    缺点:存储数据元素有上限,当达到MAX后,就不能再添加元素了


1.2    链表的概念


1>    链式存储的线性表叫做链表
1、链式存储:表示数据元素的存储地址不一定连续
2、线性表:数据元素之间存在一对一的关系
2>    链表的原理图如下

3>    链表的基础概念
 

1、节点:节点是链表的基本单位,由数据域和指针域组成
2、数据域:存放数据元素的部分
3、指针域:存放下一个节点地址的部分
4、前驱节点:当前节点的上一个节点
5、后继节点:当前节点的下一个节点
6、头节点:虚设的一个节点,数据域不存放数据元素,可以存放链表的长度
7、头指针:指向第一个节点的指针称为头指针
8、第一个节点:实际存储数据元素的链表上的第一个节点
注意:头节点的指针域其实就是头指针,也可以单独定义一个指针,指向第一个节点
4>    链表的分类
 

1、单向链表:只能从头节点或第一个节点出发,单向访问其后继节点的链表称为单向链表
2、双向链表:从头部出发,既可以访问前驱节点,也可以访问后继节点
3、循环链表:首尾相接的链表称为循环链表


二、单向链表


只能从头节点或第一个节点出发,单向访问其后继节点的链表称为单向链表


2.1    节点结构体类型


1>    头节点和普通节点数据域可以合到一起,使用一格共用体表示
2>    指针域都是指向普通节点的地址
 

//定义数据类型
typedef int datatype;
 
//定义结点类型
typedef struct Node
{
    union
    {
        int len;    //头结点数据域
        datatype data;  //普通结点数据域
    };
 
    struct Node *next;   //指针域
};Node,*NodePtr
 
 
 


2.2    创建链表


1>    在堆区申请一格头节点的空间,就创建了一个链表
2>    需要对头节点的数据域初始化链表长度,指针域初始化NULL
 

//创建链表
NodePtr list_create()
{
    //只需要在堆区申请一个头结点
    NodePtr L = (NodePtr)malloc(sizeof(Node));
    if(NULL == L)
    {
        printf("创建失败\n");
        return NULL;
    }
 
    //程序执行至此,说明头结点创建结束
    L->len = 0;    //表示链表长度为0
    L->next = NULL;      ///防止野指针
 
    printf("链表创建成功\n");
    return L;
}


 
2.3    申请节点封装数据


1>    需要将要封装的数据当做函数的参数进行传递
2>    同样在堆区申请节点,就传入的数据放入数据域
 

//申请结点封装数据函数
NodePtr apply_node(datatype e)
{
    //在堆区申请一个结点的大小
    NodePtr p = (NodePtr)malloc(sizeof(Node));
    if(NULL == p)
    {
        printf("结点申请失败\n");
        return NULL;
    }
 
    //给结点内容赋值
    p->data = e;          //数据域赋值
    p->next = NULL;        //指针域
 
    return p;
}


 
2.4    链表判空


1>    只需要判断头节点的指针域中是否为空即可
 

//链表判空
int list_empty(NodePtr L)
{
    return L->next == NULL;
}
 


2.5    头插


1>    表示将新插入的节点放入第一个节点中
2>    插入数据时,不能先将前面节点与后面节点先断开。一定要从新节点出发,指向后面的节点,然后将前驱节点指向字节
 

//头插
int list_insert_head(NodePtr L, datatype e)
{
    //判断逻辑
    if(NULL==L)
    {
        printf("链表不合法\n");
        return -1;
    }
 
    //申请结点封装数据
    NodePtr p = apply_node(e);
    if(NULL==p)
    {
        return -1;
    }
 
    //头插逻辑
    p->next = L->next;
    L->next = p;
    
    
    //表的变化
    L->len ++;
    printf("头插成功\n");
    return 0;
}
 
 


2.6    链表遍历


需要使用一个遍历指针,将每一个节点进行遍历一遍,如果该指针指向的节点不为空,就访问其数据域,向后偏移
 

//链表遍历函数
int list_show(NodePtr L)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("遍历失败\n");
        return -1;
    }
    
    printf("链表中的元素分别是:");
    //遍历逻辑
    NodePtr q = L->next;   //定义遍历指针从第一个结点出发
    while(q != NULL)
    {
        //输出数据域
        printf("%d\t", q->data);
 
        q = q->next;    //指针向后偏移一个
    }
}
 
 


2.7    通过位置查找节点


1>    参数:链表、位置
2>    返回值:对应节点的地址
 

//通过位置查找结点
NodePtr list_search_pos(NodePtr L, int pos)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<0 || pos>L->len)
    {
        printf("查找失败\n");
        return NULL;
    }
 
    //查找逻辑
    //定义遍历指针从头结点出发
    NodePtr q = L;
    for(int i=0; i<pos; i++)
    {
        q = q->next;
    }
 
    return q;     //将找到的结点地址返回
}
 


2.8    任意位置插入元素


1>    参数:链表、位置、要插入的元素
2>    返回值:int
3>    注意:必须找到要插入位置的节点的前驱节点,将前驱节点当作头节点,进行头插操作
 

//任意位置插入
int list_insert_pos(NodePtr L, int pos, datatype e)
{
    //判断逻辑
    if(NULL==L || pos<1 || pos>L->len+1)
    {
        printf("插入失败\n");
        return -1;
    }
    
    //申请结点封装数据
    NodePtr p = apply_node(e);
    if(NULL==p)
    {
        return -1;
    }
    
    //调用函数查找前驱结点
    NodePtr q = list_search_pos(L, pos-1);
    
    //插入逻辑
    p->next = q->next;
    q->next = p;
    
    //表的变化
    L->len++;
    printf("插入成功\n");
    return 0;
}


 
2.9    链表头删


1>    参数:链表
2>    返回值:int
3>    注意:需要将要删除的节点先标记一下,头节点的指针,指向第二个节点后,将标记的节点释放
 

//链表头删
int list_delete_head(NodePtr L)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("删除失败\n");
        return -1;
    }
    
    //删除三部曲
    NodePtr p = L->next;    //标记
    L->next = p->next;  //L->next->next  孤立
    free(p);            //释放
    p = NULL;
 
    //表长变化
    L->len--;
 
    printf("头删成功\n");
    return 0;
}
 


2.10    任意位置删除函数


1>    参数:链表、要删除的位置
2>    返回值:int
3>    注意:需要找到要删除的节点的前驱节点,将其当作头节点,进行头删逻辑
Plain Text
自动换行

//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
    {
        printf("删除失败\n");
        return -1;
    }
    
    //找到前驱结点
    NodePtr q = list_search_pos(L, pos-1);
    
    //删除逻辑
    NodePtr p = q->next;           //标记
    q->next = q->next->next;   //p->next 孤立
    free(p);                   //释放
    p = NULL;
 
    
    //表的变化
    L->len--;
    printf("删除成功\n");
    return 0;
}
 
 


2.11    按值查找返回位置


1>    参数:链表、要查找的值
2>    返回值:元素在链表中的位置
Plain Text
自动换行

//链表按值查找返回位置
int list_search_value(NodePtr L, datatype e)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("查找失败\n");
        return -1;
    }
    
    //查找逻辑
    //定义遍历指针从第一个结点出发
    NodePtr q = L->next;
    for(int index=1; index<=L->len; index++)
    {
        //判断当前结点的值是否为要找的数据
        if(q->data == e)
        {
            return index;
        }
 
        q = q->next;     //继续向后遍历
    }
 
    //程序执行至此,表示没找到
    printf("没找到\n");
    return -1;
}
 


2.12    按位置修改


1>    参数:链表、要修改的元素位置、要被更新的值
2>    返回值:int
3>    注意:先通过位置,找到对应的元素,更改该元素中的内容即可
Plain Text
自动换行

//链表按位置进行修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
    {
        printf("修改失败\n");
        return -1;
    }
    
    //按位置查找逻辑
    NodePtr p = list_search_pos(L, pos);
    
    //修改逻辑
    p->data = e;
 
    printf("修改成功\n");
    return 0;
}
 


2.13    按值进行修改函数


1>    参数:链表、旧值、新值
2>    返回值:int
3>    思路:先通过旧值找到位置,通过位置进行修改
Plain Text
自动换行

//按值进行修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("修改失败\n");
        return -1;
    }
    
    //按值查找位置
    int res = list_search_value(L, old_e);
    if(res == -1)
    {
        printf("没有要修改的值\n");
        return -1;
    }
    
    //按位置修改
    list_update_pos(L, res, new_e);
    
    printf("修改成功\n");
    return 0;
}
 


2.14    链表的反转


1>    参数:链表
2>    返回值:int
3>    注意:在该操作中,没有节点被删除,也没有节点被释放
 

//将链表进行翻转
void list_reverse(NodePtr L)
{
    //判断逻辑
    if(NULL==L || L->len<=1)
    {
        printf("翻转失败\n");
        return ;
    }
    
    //翻转逻辑
    NodePtr H = L->next;   //将链表元素进行托付
 
    L->next = NULL;        //自己白手起家
 
    NodePtr p = NULL;         //结点的搬运工
 
    while(H != NULL)
    {
        p = H;      //搬运第一个结点
        H = H->next;     //头指针后移
 
        //将p以头插的方式放入L中
        p->next = L->next;
        L->next = p;
    }
 
    printf("翻转成功\n");
    
}
 


2.15    链表的释放


1>    参数:链表
2>    返回值:无
3>    注意:需要先将所有的节点内存全部释放后,再将头节点释放
Plain Text
自动换行

//释放链表
void list_destroy(NodePtr L)
{
    //判断逻辑
    if(NULL == L)
    {
        return;
    }
 
    //将所有结点进行释放
    while(!list_empty(L))
    {
        //头删
        list_delete_head(L);
    }
 
    //释放头结点
    free(L);
    L = NULL;
 
    printf("释放成功\n");
}
 


2.16    代码总结


1>    linklist.h
Plain Text
自动换行

#ifndef LINKLIST_H
#define LINKLIST_H
#include<myhead.h>
 
//定义数据类型
typedef int datatype;
 
//定义结点类型
typedef struct Node
{
    union
    {
        int len;    //头结点数据域
        datatype data;  //普通结点数据域
    };
 
    struct Node *next;   //指针域
}Node, *NodePtr;
 
//创建链表
NodePtr list_create();
 
//申请结点封装数据函数
NodePtr apply_node(datatype e);
 
//链表判空
int list_empty(NodePtr L);
 
//头插
int list_insert_head(NodePtr L, datatype e);
 
//链表遍历函数
int list_show(NodePtr L);
 
//通过位置查找结点
NodePtr list_search_pos(NodePtr L, int pos);
 
//任意位置插入
int list_insert_pos(NodePtr L, int pos, datatype e);
 
//链表头删
int list_delete_head(NodePtr L);
 
//链表任意位置删除
int list_delete_pos(NodePtr L, int pos);
 
//链表按值查找返回位置
int list_search_value(NodePtr L, datatype e);
 
//链表按位置进行修改
int list_update_pos(NodePtr L, int pos, datatype e);
 
//按值进行修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e);
 
//将链表进行翻转
void list_reverse(NodePtr L);
 
//释放链表
void list_destroy(NodePtr L);
 
 
 
 
 
#endif
 
2>    linklist.c
Plain Text
自动换行

#include"linklist.h"
 
//创建链表
NodePtr list_create()
{
    //只需要在堆区申请一个头结点
    NodePtr L = (NodePtr)malloc(sizeof(Node));
    if(NULL == L)
    {
        printf("创建失败\n");
        return NULL;
    }
 
    //程序执行至此,说明头结点创建结束
    L->len = 0;    //表示链表长度为0
    L->next = NULL;      ///防止野指针
 
    printf("链表创建成功\n");
    return L;
}
 
 
 
//申请结点封装数据函数
NodePtr apply_node(datatype e)
{
    //在堆区申请一个结点的大小
    NodePtr p = (NodePtr)malloc(sizeof(Node));
    if(NULL == p)
    {
        printf("结点申请失败\n");
        return NULL;
    }
 
    //给结点内容赋值
    p->data = e;          //数据域赋值
    p->next = NULL;        //指针域
 
    return p;
}
 
 
//链表判空
int list_empty(NodePtr L)
{
    return L->next == NULL;
}
 
//头插
int list_insert_head(NodePtr L, datatype e)
{
    //判断逻辑
    if(NULL==L)
    {
        printf("链表不合法\n");
        return -1;
    }
 
    //申请结点封装数据
    NodePtr p = apply_node(e);
    if(NULL==p)
    {
        return -1;
    }
 
    //头插逻辑
    p->next = L->next;
    L->next = p;
    
    
    //表的变化
    L->len ++;
    printf("头插成功\n");
    return 0;
}
 
 
//链表遍历函数
int list_show(NodePtr L)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("遍历失败\n");
        return -1;
    }
    
    printf("链表中的元素分别是:");
    //遍历逻辑
    NodePtr q = L->next;   //定义遍历指针从第一个结点出发
    while(q != NULL)
    {
        //输出数据域
        printf("%d\t", q->data);
 
        q = q->next;    //指针向后偏移一个
    }
    printf("\n");
}
 
//通过位置查找结点
NodePtr list_search_pos(NodePtr L, int pos)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<0 || pos>L->len)
    {
        printf("查找失败\n");
        return NULL;
    }
 
    //查找逻辑
    //定义遍历指针从头结点出发
    NodePtr q = L;
    for(int i=0; i<pos; i++)
    {
        q = q->next;
    }
 
    return q;     //将找到的结点地址返回
}
 
 
 
//任意位置插入
int list_insert_pos(NodePtr L, int pos, datatype e)
{
    //判断逻辑
    if(NULL==L || pos<1 || pos>L->len+1)
    {
        printf("插入失败\n");
        return -1;
    }
    
    //申请结点封装数据
    NodePtr p = apply_node(e);
    if(NULL==p)
    {
        return -1;
    }
    
    //调用函数查找前驱结点
    NodePtr q = list_search_pos(L, pos-1);
    
    //插入逻辑
    p->next = q->next;
    q->next = p;
    
    //表的变化
    L->len++;
    printf("插入成功\n");
    return 0;
}
 
//链表头删
int list_delete_head(NodePtr L)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("删除失败\n");
        return -1;
    }
    
    //删除三部曲
    NodePtr p = L->next;    //标记
    L->next = p->next;  //L->next->next  孤立
    free(p);            //释放
    p = NULL;
 
    //表长变化
    L->len--;
 
    printf("头删成功\n");
    return 0;
}
 
//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
    {
        printf("删除失败\n");
        return -1;
    }
    
    //找到前驱结点
    NodePtr q = list_search_pos(L, pos-1);
    
    //删除逻辑
    NodePtr p = q->next;           //标记
    q->next = q->next->next;   //p->next 孤立
    free(p);                   //释放
    p = NULL;
 
    
    //表的变化
    L->len--;
    printf("删除成功\n");
    return 0;
}
 
 
//链表按值查找返回位置
int list_search_value(NodePtr L, datatype e)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("查找失败\n");
        return -1;
    }
    
    //查找逻辑
    //定义遍历指针从第一个结点出发
    NodePtr q = L->next;
    for(int index=1; index<=L->len; index++)
    {
        //判断当前结点的值是否为要找的数据
        if(q->data == e)
        {
            return index;
        }
 
        q = q->next;     //继续向后遍历
    }
 
    //程序执行至此,表示没找到
    printf("没找到\n");
    return -1;
}
 
 
//链表按位置进行修改
int list_update_pos(NodePtr L, int pos, datatype e)
{
    //判断逻辑
    if(NULL==L || list_empty(L) || pos<1 || pos>L->len)
    {
        printf("修改失败\n");
        return -1;
    }
    
    //按位置查找逻辑
    NodePtr p = list_search_pos(L, pos);
    
    //修改逻辑
    p->data = e;
 
    printf("修改成功\n");
    return 0;
}
 
 
 
//按值进行修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e)
{
    //判断逻辑
    if(NULL==L || list_empty(L))
    {
        printf("修改失败\n");
        return -1;
    }
    
    //按值查找位置
    int res = list_search_value(L, old_e);
    if(res == -1)
    {
        printf("没有要修改的值\n");
        return -1;
    }
    
    //按位置修改
    list_update_pos(L, res, new_e);
    
    printf("修改成功\n");
    return 0;
}
 
 
 
//将链表进行翻转
void list_reverse(NodePtr L)
{
    //判断逻辑
    if(NULL==L || L->len<=1)
    {
        printf("翻转失败\n");
        return ;
    }
    
    //翻转逻辑
    NodePtr H = L->next;   //将链表元素进行托付
 
    L->next = NULL;        //自己白手起家
 
    NodePtr p = NULL;         //结点的搬运工
 
    while(H != NULL)
    {
        p = H;      //搬运第一个结点
        H = H->next;     //头指针后移
 
        //将p以头插的方式放入L中
        p->next = L->next;
        L->next = p;
    }
 
    printf("翻转成功\n");
    
}
 
//释放链表
void list_destroy(NodePtr L)
{
    //判断逻辑
    if(NULL == L)
    {
        return;
    }
 
    //将所有结点进行释放
    while(!list_empty(L))
    {
        //头删
        list_delete_head(L);
    }
 
    //释放头结点
    free(L);
    L = NULL;
 
    printf("释放成功\n");
}
 
3>    main.c
Plain Text
自动换行

#include"linklist.h"
 
int main(int argc, const char *argv[])
{
    
    //调用函数创建一个链表
    NodePtr L = list_create();
    if(NULL == L)
    {
        return -1;
    }
 
    //调用头插函数
    list_insert_head(L, 520);
    list_insert_head(L, 1314);
    list_insert_head(L, 666);
    list_insert_head(L, 999);
    
    //调用遍历函数
    list_show(L);
 
    //调用任意位置插入函数
    list_insert_pos(L, 1, 100);
    list_insert_pos(L, 3, 100);
    list_insert_pos(L, L->len+1, 100);
    list_show(L);
 
    //调用头删函数
    list_delete_head(L);
    list_delete_head(L);
    list_show(L);
 
    //调用删除函数
    list_delete_pos(L, 1);
    list_delete_pos(L, 2);
    list_delete_pos(L, L->len);
    list_show(L);
 
    //调用按值查找位置
    int res = list_search_value(L, 666);
    if(res != -1)
    {
        printf("您要找的数据在链表的第%d个位置\n", res);
    }
 
    //调用按位置进行修改函数
    list_update_pos(L, 1, 12345);
    list_show(L);
 
    //调用按值修改函数
    list_update_value(L, 12345, 6789);
    list_show(L);
 
    //调用翻转函数
    list_reverse(L);
    list_show(L);
 
    //调用释放函数
    list_destroy(L);
    L = NULL;
 
 
    return 0;
}

链表的排序

int pai(NodePtrL)
{
  if (L == NULL || L->len <= 1)
  {
    printf("排序失败");
    return -1;
  }
  for (int i = 1; i < L->len; i++)
  {
   NodePtr a = L;
    while (a->next->next != NULL)
    {
      if (a->next->data > a->next->next->data)
      {
        NodePtr s = a->next;
        a->next = a->next ->next;
        s->next= a->next->next;
        a->next->next= s;
      }
      a = a->next;
    }
  }
  printf("排序成功\n");
  return 0;
}

链表反转递归

int list_turn(Node_ptr L)
{
  static int i=0;//插入位置
  node_ptr a = L->next;
    if(L->len==i+1)//结束条件
   {
     L=a;
     i=0;//i的初始化
     return 0;
   }
  while (a->next->next != NULL)//找到倒数第二个元素
  {
    a = a->next;
  } 
   i++;
list_insert_pos(L, i,a->next->data);//
  L->len--;
  a->next = NULL;//最后一个元素置空
  return list_turn(L);
}

text.h

#ifndef MAX
#define MAX 100 //班级最大值
//定义学生类型
struct Stu
{
    char name[20];//姓名
    int age;//年龄
    double score;//成绩
};
//定义班级类型
struct Class
{
    struct Stu student[MAX];       //存放学生的容器
    int size;                      //实际人数
};
void *create(int sum);//创造结构体
void in(struct Class *q);//输入
void print(struct Class *q);//输出
void ch(struct Class *q);//选择最好与最差
void paixun(struct Class *q);//降序排序
void destroy(struct Class *q);//销毁
int  list_add(struct Class *q,struct Stu e);
int  list_delete(struct Class *q,int pos);
int  list_find(struct Class *q,char e[]);
int  list_gai(struct Class *q,int pos, struct Stu e);
int inserts(struct Class *q,int pos,struct Stu e);
#endif
ee.c

#include <myhead.h>
#include "text.h"
void *create(int sum)
{
    struct Class *ptr = (struct Class *)malloc(sizeof(struct Class) * sum); //定义一个结构体指针接受开辟的堆区空间
    if (NULL == ptr)                                                        //实际空间为0
    {
        printf("申请失败\n");
        return NULL;
    }
    //程序执行至此,表示内存申请成功
    //给内存空间进行初始化
    memset(ptr, 0, sizeof(int) * sum);

    //将内存地址返回
    return ptr;
}
void in(struct Class *q)
{
    for (int i = 0; i < q->size; i++) //遍历结构体的student数组
    {
        printf("请输入第%d位学生姓名\n", i + 1);
        scanf("%s", q->student[i].name);
        printf("请输入第%d位学生年龄\n", i + 1);
        scanf("%d", &q->student[i].age);
        printf("请输入第%d位学生的成绩\n", i + 1);
        scanf("%lf", &q->student[i].score);
    }
}
void print(struct Class *q)
{
    if (q == NULL) //无数据
    {
        printf("输出失败\n");
        return;
    }
    printf("姓名\t年龄\t成绩\n");     //打印开头名称
    for (int i = 0; i < q->size; i++) //遍历结构体的student数组
    {

        printf("%s\t%d\t%.2f\n", q->student[i].name, q->student[i].age, q->student[i].score); //输出各个数据
    }
}
void ch(struct Class *q)
{
    if (q == NULL) //数据为空无输出
    {
        printf("选择失败\n");
        return;
    }
    int maxi = 0, mini = 0;           //定义最大最小值小标
    for (int i = 0; i < q->size; i++) //遍历结构体的student数组
    {
        if (q->student[maxi].score < q->student[i].score) //成绩最大值比数组中数据小
        {
            maxi = i; //下标转移
        }
        if (q->student[mini].score > q->student[i].score) //成绩最小值比数组中数据大
        {
            mini = i; //下标转移
        }
    }
    printf("成绩最高学生姓名%s\t年龄%d\t成绩%.2f\n", q->student[maxi].name, q->student[maxi].age, q->student[maxi].score); //输出最好学生的信息
    printf("成绩最低学生姓名%s\t年龄%d\t成绩%.2f\n", q->student[mini].name, q->student[mini].age, q->student[mini].score); //输出最差学生的信息
}
void paixun(struct Class *q)
{
    for (int i = 1; i < q->size; i++) //外循环
    {
        for (int j = 0; j < q->size - 1; j++)                  //遍历结构体的student数组
            if (q->student[j].score < q->student[j + 1].score) //读取student[j]的score与student[j+1]的score进行比较
            {
                struct Stu temp;                       //定义一个学生类型
                strcpy(temp.name, q->student[j].name); //将student[j]赋值给temp
                temp.age = q->student[j].age;
                temp.score = q->student[j].score;
                strcpy(q->student[j].name, q->student[j + 1].name); //将student[j+1]赋值给student[j]
                q->student[j].age = q->student[j + 1].age;
                q->student[j].score = q->student[j + 1].score;
                strcpy(q->student[j + 1].name, temp.name); //将temp赋值给student[j+1]
                q->student[j + 1].age = temp.age;
                q->student[j + 1].score = temp.score;
            }
    }
    printf("排序成功\n"); //提示成功
}
void destroy(struct Class *q)
{
    //释放内存
    if (NULL != q)
    {
        free(q); //释放空间
        q = NULL;
    }
}
int list_add(struct Class *q, struct Stu e)
{
    if (NULL == q )
    {
        printf("添加失败\n");
        return -1;
    }
    q->student[q->size].age = e.age;
    q->student[q->size].score = e.score;
    strcpy(q->student[q->size].name, e.name);
    q->size++;
    printf("添加成功\n");
}
int list_delete(struct Class *q, int pos)
{
    if (NULL == q || pos < 0 || pos >= q->size)
    {
        printf("删除失败\n");
        return -1;
    }
    for (int i = pos + 1; i < q->size; i++)
    {
        q->student[i - 1].age = q->student[i].age;
        q->student[i - 1].score = q->student[i].score;
        strcpy(q->student[i - 1].name, q->student[i].name);
    }
    q->size-- ;
    printf("删除成功\n");
    return 0;
}
int list_find(struct Class *q, char e[])
{
    if (q == NULL)
    {
        return -1;
    }
    for (int i = 0; i < q->size; i++)
    {
        if (strcmp(e,q->student[i].name)==0)
        {
            return i;
        }
    }
    printf("没找到\n");
    return -1;

}
int list_gai(struct Class *q, int pos, struct Stu e)
{
    if (q == NULL || pos >= q->size)
    {
        return -1;
    }
    q->student[pos].score = e.score;
    q->student[pos].age=e.age;
    strcpy(q->student[pos].name,e.name);

    printf("修改成功");
    return 0;
}
int inserts(struct Class *q, int pos, struct Stu e)
{
    if (NULL == q || pos > q->size || pos < 0)
    {
        printf("插入失败\n");
        return -1;
    }
    for (int i = q->size -1; i >= pos; i--)
    {
        q->student[i +1].age = q->student[i].age;
        q->student[i +1].score = q->student[i].score;
        strcpy(q->student[i +1].name, q->student[i].name);
    }
    q->student[pos].score = e.score;
    q->size++;
    printf("插入成功\n");
}
y.c

#include <myhead.h>
#include "text.h"
int main()
{
    int N = 0;
    int sum = 0;
    int pos = 0;
    struct Stu w;
    char r[20];
    char k = ' ';
    while (1)
    {
        printf("*************菜单*************\n");
        printf("1>创建班级\n2>班级学生信息录入\n3>将班级学生按成绩进行降序排序\n4>输出班级中成绩最好和最差学生的信息\n5>输出信息\n6>销毁班级\n7>增加学生数据\n8>删除学生数据\n9>修改学生信息\n10>查找学生\n0>退出\n"); //打印菜单
        printf("******************************\n");
        scanf("%d", &N); //接受菜单变量
        switch (N)       //switch语句实现菜单功能
        {
        case 1:
            printf("请输入班级人数\n");
            scanf("%d", &sum); //接受用户输入的数字
            struct Class *q = (struct Class *)create(sum);
            q->size = sum; //sum赋值给结构体中对应变量
            break;
        case 2:
            in(q);
            break;
        case 3:
            paixun(q);
            break;
        case 4:
            ch(q);
            break;
        case 5:
            print(q);
            break;
        case 6:
            destroy(q);
            q = NULL;
            break;
        case 7:
            printf("请输入学生姓名\n");
            scanf("%s", w.name);
            printf("请输入学生年龄\n");
            scanf("%d", &w.age);
            printf("请输入学生的成绩\n");
            scanf("%lf", &w.score);
            list_add(q, w);
            break;
        case 8:
            printf("请输入位置");
            scanf("%d", &pos);
            list_delete(q, pos - 1);
            break;
        case 0:
            return 0; //结束程序
        case 9:

            printf("请输入位置");
            scanf("%d", &pos);
            printf("请输入修改后的学生姓名\n");
            scanf("%s", w.name);
            printf("请输入修改后的学生年龄\n");
            scanf("%d", &w.age);
            printf("请输入修改后的学生的成绩\n");
            scanf("%lf", &w.score);
            list_gai(q, pos - 1, w);
            break;
        case 10:
            printf("请输入要查找的学生姓名\n");
            scanf("%s", r);
            printf(" 在第%d位置\n", list_find(q, r) + 1);
            break;
        default:
            break;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值