双向循环链表实践---学生管理系统

写在前面

在看Linux源码时,经常会涉及到驱动和设备的匹配,如果想弄清楚匹配过程,就要理解双向循环链表。
这篇文章是理解了Linux的list.h文件后自己的实现应用。

理论知识

这里写图片描述

实现步骤

链表的常用的节点操作如下:
增加、删除、查找

首先定义一个结构体,存放学生的信息

struct student {
    int number;
    char id[20];   //学号
    char name[20]; //姓名
    float score;   //成绩
    struct student *next;
    struct student *prev;
};
创建头节点
  1. 创建头指针
  2. 初始化头指针
    1. 分配内存
    2. 自己指向自己
struct student *head = NULL;

/*create head node*/
void init(void)  
{
    printf("%s\n", __func__);
    head = (struct student *)malloc(sizeof(struct student));
    head->next = head;   
    head->prev = head;
}
增加节点
void add_student(void)
{
    /*增加一个学生的信息*/
    char new_id[20] = {0};
    char new_name[20] = {0};
    float new_score = 0.00;
    memset(new_id, 0, sizeof(new_id));
    memset(new_name, 0, sizeof(new_name));

    printf("%s\n", __func__);

    printf("enter the id:\n");
    scanf("%s", new_id);

    /*id是唯一的依据,所以要进行去重操作*/
    if(have_same_id(new_id)){
        printf("hava same id\n");
        goto have_same_id;
    }

    printf("enter the name:\n");
    scanf("%s", new_name);
    printf("enter the score:\n");
    scanf("%f", &new_score);

    /*增加新节点核心操作*/
    struct student * new_node = (struct student *)malloc(sizeof(struct student));
    struct student * last_node = head->prev;
    last_node->next = new_node;
    new_node->prev = last_node;
    head->prev = new_node;
    new_node->next = head;

    count++;
    /*节点信息填充*/
    new_node->number = count;
    memset(new_node->id, 0, sizeof(new_node->id));
    memset(new_node->name, 0, sizeof(new_node->name));
    strcpy(new_node->id, new_id);
    strcpy(new_node->name, new_name);
    new_node->score = new_score;

    printf("add student ok!\n");

    list_all_student();

have_same_id:
    return ;
}
#define HAVE_SAME_ID    1
#define NO_SAME_ID      0

int have_same_id(char *id)
{
    struct student *pos = NULL;
    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            return HAVE_SAME_ID;
        }
    }
    return NO_SAME_ID;
}
删除节点
void delete_student()
{
    struct student * pos = NULL;
    char id[20];
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));
    /*以ID为唯一凭证*/
    printf("enter the id that you want delete:\n");
    scanf("%s", id);

    //删除节点核心实现
    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("delete\t%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            pos->prev->next = pos->next;
            pos->next->prev = pos->prev;
            free(pos);
            delete_student_fixed_count(); //删除节点后,修复节点中number标记
            return;
        }
    }

    printf("no the same id, pleace check it again\n");

}
void delete_student_fixed_count(void)
{
    struct student *pos = NULL; 
    int i = 0;
    count--;
    for(pos = head->next, i = 1; pos != head; pos = pos->next, i++)
    {
        pos->number = i;
    }
    i--;
    if(i != count){
        printf("i = %d\t, count = %d\n", i, count);
        printf("count error\n");
    }
    list_all_student();

}
查找节点

查找结点比较简单,根据一个值遍历所有节点即可
示例代码中,以学生ID为唯一参考

void search_student_score(void)
{
    struct student * pos = NULL;
    char id[20];
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));

    printf("enter the id that want to search:\n");
    scanf("%s", id);

    //核心代码
    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("find the id:\n");
            printf("\tid\t\t\tname\t\t\tsorce\n");
            printf("%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            return;
        }
    }
    printf("sorry, can not find the id info\n");

}
释放节点

由于内存空间是使用malloc进行分配的,所有要用free进行手动释放,释放某一个节点比较简单,释放所有节点相对复杂点,其实就是遍历所有节点,并一一删除。

释放一个节点
  1. 以ID为标记,找到要释放的节点
  2. 注意修改节点的next和prev节点
  3. 释放该节点的内存
void delete_student()
{
    struct student * pos = NULL;
    char id[20];
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));
    printf("enter the id that you want delete:\n");
    scanf("%s", id);

    //核心实现
    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("delete\t%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            pos->prev->next = pos->next;
            pos->next->prev = pos->prev;
            free(pos);
            delete_student_fixed_count();
            return;
        }
    }

    printf("no the same id, pleace check it again\n");

}
删除所有节点

结束程序时,要删除所有分配过的内存,防止内存泄漏
该操作就是遍历所有节点并释放内存

void free_all_memory()
{
    struct student * pos = head->next;
    printf("%s\n", __func__);
    for(; pos != head; )
    {
        head->next = pos->next;
        pos->next->prev = head;
        printf("\tdelete node->number = %d\n", pos->number);   //显示所有要删除的节点,防止有内存泄露
        free(pos);
        pos = head->next;
    }
    printf("\tdelete head node\n");
    free(head);
}
完整代码

此示例代码,已经实验过,无内存泄漏,所有功能实现。

/*************************
    双向循环链表练习
      学生管理系统
       2018.01.27
        cxiaolei
*************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HAVE_SAME_ID    1
#define NO_SAME_ID      0

struct student {
    int number;
    char id[20];   //学号
    char name[20]; //姓名
    float score;//成绩
    struct student *next;
    struct student *prev;
};

int count = 0;

struct student *head = NULL;

/*create head node*/
void init(void)  
{
    printf("%s\n", __func__);
    head = (struct student *)malloc(sizeof(struct student));
    head->next = head;   
    head->prev = head;
}

void list_all_student(void)
{
    struct student *pos = NULL;
    printf("%s\n", __func__);
    printf("\n\n\n\tid\t\t\tname\t\t\tsorce\n");
    for(pos = head->next; pos != head; pos = pos->next)
    {
        printf("%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
    }
    printf("\n\n\n%s : end\n", __func__);
}

int have_same_id(char *id)
{
    struct student *pos = NULL;
    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            return HAVE_SAME_ID;
        }
    }
    return NO_SAME_ID;
}

void delete_student_fixed_count(void)
{
    struct student *pos = NULL; 
    int i = 0;
    count--;
    for(pos = head->next, i = 1; pos != head; pos = pos->next, i++)
    {
        pos->number = i;
    }
    i--;
    if(i != count){
        printf("i = %d\t, count = %d\n", i, count);
        printf("count error\n");
    }
    list_all_student();

}

void add_student(void)
{
    char new_id[20] = {0};
    char new_name[20] = {0};
    float new_score = 0.00;
    memset(new_id, 0, sizeof(new_id));
    memset(new_name, 0, sizeof(new_name));

    printf("%s\n", __func__);

    printf("enter the id:\n");
    scanf("%s", new_id);

    if(have_same_id(new_id)){
        printf("hava same id\n");
        goto have_same_id;
    }

    printf("enter the name:\n");
    scanf("%s", new_name);
    printf("enter the score:\n");
    scanf("%f", &new_score);

    struct student * new_node = (struct student *)malloc(sizeof(struct student));
    struct student * last_node = head->prev;
    last_node->next = new_node;
    new_node->prev = last_node;
    head->prev = new_node;
    new_node->next = head;

    count++;

    new_node->number = count;
    memset(new_node->id, 0, sizeof(new_node->id));
    memset(new_node->name, 0, sizeof(new_node->name));
    strcpy(new_node->id, new_id);
    strcpy(new_node->name, new_name);
    new_node->score = new_score;

    printf("add student ok!\n");

    list_all_student();

have_same_id:
    return ;
}

void delete_student()
{
    struct student * pos = NULL;
    char id[20];
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));
    printf("enter the id that you want delete:\n");
    scanf("%s", id);

    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("delete\t%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            pos->prev->next = pos->next;
            pos->next->prev = pos->prev;
            free(pos);
            delete_student_fixed_count();
            return;
        }
    }

    printf("no the same id, pleace check it again\n");

}

void search_student_score(void)
{
    struct student * pos = NULL;
    char id[20];
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));

    printf("enter the id that want to search:\n");
    scanf("%s", id);

    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("find the id:\n");
            printf("\tid\t\t\tname\t\t\tsorce\n");
            printf("%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            return;
        }
    }
    printf("sorry, can not find the id info\n");

}

void modify_student_score(void)
{
    struct student * pos = NULL;
    char id[20];
    float score = 0.00;
    printf("%s\n", __func__);

    memset(id, 0, sizeof(id));

    printf("enter the id that want to modify:\n");
    scanf("%s", id);
    printf("enter the score that want to modify:\n");
    scanf("%f", &score);

    for(pos = head->next; pos != head; pos = pos->next)
    {
        if(strcmp(pos->id, id) == 0){
            printf("find the id and modify the score:\n");
            pos->score = score;
            printf("\tid\t\t\tname\t\t\tsorce\n");
            printf("%d\t%s\t\t\t%s\t\t\t%f\n", pos->number, pos->id, pos->name, pos->score);
            return;
        }
    }
    printf("sorry, can not find the id info\n");
}

void free_all_memory()
{
    struct student * pos = head->next;
    struct student * pos_next = NULL;
    printf("%s\n", __func__);
    for(; pos != head; )
    {
        //pos_next = pos->next;
        head->next = pos->next;
        pos->next->prev = head;
        printf("\tdelete node->number = %d\n", pos->number);
        free(pos);
        pos = head->next;
    }
    printf("\tdelete head node\n");
    free(head);
}

int main(void)
{
    int user_select = 0;

    init();

    printf("简单的学生管理系统");
    while(1){
        printf("function select\n");
        printf("\t1. add a student info\n\t2. delete a student info\n\t3. search student score\n\t4. modify student score\n\t5. list all student\n\t0. quit the application\n");
        scanf("%d", &user_select);
        switch(user_select){
            case 0:{
                free_all_memory();
                printf("the application will quit\n");
                return 0;
            }           
            case 1:{
                add_student();
                break;
            }
            case 2:{
                delete_student();
                break;
            }       
            case 3:{
                search_student_score();
                break;
            }
            case 4:{
                modify_student_score();
                break;
            }
            case 5:{
                list_all_student();
                break;
            }
            default:{
                printf("enter error\n");
                free_all_memory();
                break;
            }
        }
    }
    return 0;
}
  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值