新生与链表

  我写的这些都是我自己学习的时候所掌握的知识点,以及自己时常写代码留下的注释,最后加上了一些个人发现同学的一些问题,索性发来出来

#include <stdio.h>//标准输入输出头文件
#include <stdlib.h>//用于使用malloc函数的头文件


//这是typedef标识符用法,这个node我们不用,只做讲解,
/*typedef struct node{
    //数据域
    int m_id;
    int m_money;
    //指针域
    struct Node *next;
}*linklist,node;
这样写相当于给node起了个小名,这个小名天生就是指针型标识符,
比如linklist p就相当于node *p;因此我们可以起个小名叫node,
这样就不用每次写struct node a;来定义了。直接node a;就行  */

//结构体和类名的首字母大写,这是规范,c语言是区分大小写的
//结点结构体
typedef struct Node{
    //数据域
    int m_id;
    int m_money;
    //指针域
    struct Node *next;
}Node,*linklist;


//第一个函数,先来初始化链表
void Init_linklist(linklist test){
    /*先来讲一下新建结点,(Node*)的意义有两层,
    一是告诉malloc,按Node结构体的样子分配内存,
    二是把malloc返回的地址强制转换成Node*的类型
    sizeof是测出Node的长度,如果你知道string并打算在结点里使用
    那么最好学会c++的new,要不然在添加结点的时候,程序时常崩溃
    不报错的那种崩溃*/
     test = (Node *)malloc(sizeof(Node));
    //给新建结点的指针域归为null;一定要初始化,要不然会成野指针的
    test->next=NULL;
}

//添加结点
void Add_node(linklist test){
    //一个结点的指针,依据它来添加元素
    linklist temp;
    //初始化一个p,让他和test相同,避免操作test
    linklist p=test;
    //分配内存给temp
    temp=(linklist)malloc(sizeof(Node));
    //接下来可以先输入,也可以吧temp安放在末端位置,我用switch来分开两种情况
    //其实没有区别
    int sel=0;//select的简写
    printf("请输入选择(1-先输入 2-后输入):");
    scanf("%d",&sel);
    switch(sel)
    {
        case 1: {
                //这个是先输入
                printf("输入数据\n");
                printf("请输入id:\n");
                scanf("%d",&temp->m_id);
                printf("请输入money:\n");
                scanf("%d",&temp->m_money);
                printf("输入完成\n");
                system("pause");//按任意键继续的函数
                while(p->next)//p的next为空指针时结束循环
                {
                    p=p->next;//使p移向链表末端
                }
                printf("移动指针完成\n");
                system("pause");//按任意键继续的函数
                //连接新结点
                p->next=temp;
                //把新结点的next置空;防止野指针出现
                temp->next=NULL;
                
                break;//防止你们跑了发现问题,我来个跳出
                }
        case 2: {
                //这个是先判断
                while(p->next)//p的next为空指针时结束循环
                {
                    p=p->next;//使p移向链表末端
                }
                printf("移动指针完成\n");
                system("pause");//按任意键继续的函数
                //输入数据
                printf("输入数据\n");
                printf("请输入id:\n");
                scanf("%d",&temp->m_id);
                printf("请输入money:\n");
                scanf("%d",&temp->m_money);
                printf("输入完成\n");
                system("pause");//按任意键继续的函数
                //连接新结点
                p->next=temp;
                //把新结点的next置空;防止野指针出现
                temp->next=NULL;
                
                break;//防止你们跑了发现问题,我来个跳出
                }
    }
    printf("添加成功\n");

}
//用const是为了防止误修改,const的英语就是恒定的(adj);常数(n)
    
void Show_linklist(const linklist test)
   {
    //还是一样,不操控test,另来一个指针来移动
    linklist p=test->next;
    //这是打印的表头格式
    printf("id\tmoney\n");
    //用循环,直到末结点
    while(p)
    {   
        //打印数据
        printf("%d\t",p->m_id); 
        printf("%d\n",p->m_money);
        //每次循环完了,指针后移
        p=p->next;
    }
}

//删除函数
void Delete_node(linklist test)
//根据结构体的特点,可以设置多种删除
//比如按名字查找删除,按电话,按序号,按id,这里只有一个id
{   /*这里是双指针法,毕竟删除一个结点,需要把这个结点的
    前后结点连接起来,保证链表依旧连贯,用一个指针指向删除结点的
    前驱结点,把这个前驱结点的next指向另个一个指针
    (这个指针指向删除结点) 的next,这样两个结点就连接起来了*/
    linklist temp=NULL;
    linklist p=test;
    //为什么要来个Node t保存要查询的结点id?
    /*因为实际运用可以有多种查询方式,而这些查询都会依据
    Node的元素来查询*/
    Node t;
    //立个flag做标记
    int flag=0;
    //下面就开始查询了,查到了就删除,查不到就依据flag判断
    printf("请输入删除人id:\n");
    scanf("%d",&t.m_id);
    //依旧遍历一下链表
    while(p->next)
     {  
        //因为上面我是将temp先置空,所以这里先让他指向第一个结点
        temp=p->next;
        //下面就是遍历判断了
        if(temp->m_id==t.m_id)
        {   
            //这不陌生把
            printf("删除人id:");
            printf("%d\t",temp->m_id);
            printf("删除人的财产:");
            printf("%d\n",temp->m_money);
            printf("已删除此人!\n");
            //查到了就修改flag
            flag=1;
            //更新结点连接
            p->next=temp->next;
            //释放被删除的结点
            free(temp);
            break;
        }
        //没有退出就移动指针
        p=p->next;
     }
     //这里就是告诉你链表有没有这个结点,没有也会给个提示
     if(flag==0)
     {
        printf("查无此人!\n");
     }
}
//查找函数
void Query_node(linklist test)
{   
    //这里就是和上面一样的用法
    linklist p=test;
    Node temp;
    int flag=0;
    //查找开始
    printf("请输入查找id:\n"); 
    scanf("%d",&temp.m_id);
    //select的简写
    int sel;
    //因为实际需要,一般都是查出全部的结点,但有时候只用查一个来减少时间
    //毕竟查全部就相当于遍历全部结点,而查一个结点,可能查到半路就停了
    printf("请输入查找第一个人还是查找全部人(1-单人 2-全部人):\n");
    //我用Switch是为了方便后续添加功能
    scanf("%d",&sel);
    switch (sel)
    {   
        //这两个的区别基本上只有是否用了break
        case 1:while(p->next)
                {
                if(p->m_id==temp.m_id)
                {
                    printf("id\tmoney\n");
                    printf("%d\t%d\n",p->m_id,p->m_money);
                    flag=1;
                    //查到一个就退出
                    break;
                }
                p=p->next;
                }
        case 2: {
                while(p->next)
                {   printf("id\tmoney\n");
                    if(p->m_id==temp.m_id)
                    {
                        printf("%d\t%d\n",p->m_id,p->m_money);
                        //写flag=1也可以,我是为了和上面来个区分
                        flag++;
                    }
                    p=p->next;
                }
                }
    }
    if(flag==0)
    {
        printf("查无此人!\n");
    }
}
//清空函数
void Clear_linklist(linklist test)
{   
    printf("开始清空!\n");
    //一样的双指针法,每个结点都要释放
    linklist p1,p2;
    p1=test->next;   
    while(p1->next)
    {
    p2=p1->next;
    free(p1);
    p1=p2;
    }
    //最后一定一定要给头结点的next置空,要不然会成为野指针的
    //最后一定一定要给头结点的next置空,要不然会成为野指针的
    //最后一定一定要给头结点的next置空,要不然会成为野指针的
    test->next=NULL;
    printf("已清空!\n");
}
//修改函数
//modify就是英文修改
void Modify_node(linklist test)
{   
    //这里就没有什么好说的了,都是上面讲过的
    linklist p=test;
    Node temp;
    int flag=0;
    printf("请输入修改人的id:\n");
    scanf("%d",&temp.m_id);
    while(p->next)
    {
        p=p->next;
        if(p->m_id==temp.m_id)
        {
            printf("请输入被修改人的新信息:\n");
            printf("请输入id:\n");
            scanf("%d",&p->m_id);
            printf("请输入money:\n");
            scanf("%d",&p->m_money);
            printf("修改完成!\n");
            flag=1;
            break;
        }
        
    }
    if(flag==0)
    {
        printf("查无此人!\n");
    }
}

//主函数,因为我的函数都在main前,所以不用声明
int main(){
    //声明一个链表
    linklist head;
    //初始化
    Init_linklist(head);
    //告诉我成功了
    printf("成功\n");
    //添加函数
    Add_node(head);
    //打印函数
    Show_linklist(head);
    //删除函数
    Delete_node(head);
    //显示删除后的链表
    Show_linklist(head);
    //查找函数
    Query_node(head);
    //修改函数
    Modify_node(head);
    Show_linklist(head);
    //清空链表
    Clear_linklist(head);
    Show_linklist(head);
    system("pause");//按任意键继续的函数  
    return 0;
}
/*一些关于程序设计的命名规范,请务必了解学会,不要到了
学完了还只会用a,b,c命名,即使英语和我一样都很差,但也要
会用翻译软件啊
1,函数命名,首字母大写,前面加上功能,比如Add这样,可以用下划线"_",也可以不用
2,变量命名,需要大量使用的变量,比如
                                1.结构体和类成员 m_id
                                2.普通变量 i_sum,f_sum
                                3.全局变量 g_hight
                                4.常量 c_pai
                                5.静态变量 s_pai
3,宏定义的东西一般是全部大写 such as:#define MAX 1000
4,文件命名,单个文件的时候你写1.cpp这当然没问题,但是当你写多个文件的时候
  还这样写怕不是要搞死人,一般大型程序里,各种定义声明是分开的,每个源文件名字都体现了功能*/

没有费心思去搞一个目录啥的,就是简单检查了一遍是否可以跑

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题属于编程问题,可以回答。 以下是建立链表的程序示例: #include <stdio.h> #include <stdlib.h> typedef struct student { int id; // 学号 char name[20]; // 姓名 char gender[5]; // 性别 char birth[20]; // 出生日期 struct student *next; // 指向下一个节点的指针 } Student; // 在链表中插入新节点 void insert_node(Student *head, Student *new_node) { Student *p = head; while (p->next != NULL && p->next->id < new_node->id) { p = p->next; } new_node->next = p->next; p->next = new_node; } // 打印链表中所有节点的信息 void print_list(Student *head) { Student *p = head->next; while (p != NULL) { printf("学号:%d\t姓名:%s\t性别:%s\t出生日期:%s\n", p->id, p->name, p->gender, p->birth); p = p->next; } } int main() { // 初始化头节点和5个学生信息节点 Student *head = (Student *)malloc(sizeof(Student)); head->next = NULL; Student *stu1 = (Student *)malloc(sizeof(Student)); stu1->id = 1; strcpy(stu1->name, "张三"); strcpy(stu1->gender, "男"); strcpy(stu1->birth, "1999-01-01"); stu1->next = NULL; Student *stu2 = (Student *)malloc(sizeof(Student)); stu2->id = 3; strcpy(stu2->name, "李四"); strcpy(stu2->gender, "女"); strcpy(stu2->birth, "1999-02-01"); stu2->next = NULL; Student *stu3 = (Student *)malloc(sizeof(Student)); stu3->id = 5; strcpy(stu3->name, "王五"); strcpy(stu3->gender, "男"); strcpy(stu3->birth, "1999-03-01"); stu3->next = NULL; Student *stu4 = (Student *)malloc(sizeof(Student)); stu4->id = 7; strcpy(stu4->name, "赵六"); strcpy(stu4->gender, "女"); strcpy(stu4->birth, "1999-04-01"); stu4->next = NULL; Student *stu5 = (Student *)malloc(sizeof(Student)); stu5->id = 9; strcpy(stu5->name, "刘七"); strcpy(stu5->gender, "男"); strcpy(stu5->birth, "1999-05-01"); stu5->next = NULL; // 将5个学生信息节点插入链表 insert_node(head, stu1); insert_node(head, stu2); insert_node(head, stu3); insert_node(head, stu4); insert_node(head, stu5); // 键盘输入新生信息节点 Student *new_node = (Student *)malloc(sizeof(Student)); printf("请输入新生信息(学号、姓名、性别、出生日期,以空格隔开):"); scanf("%d %s %s %s", &new_node->id, new_node->name, new_node->gender, new_node->birth); // 将新生信息节点插入链表 insert_node(head, new_node); // 打印链表中所有节点的信息 print_list(head); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值