C语言数据结构之单链表---链表&数据分离(从零写一个单链)

了解更多知识请点我:学习C语言之路(汇总篇)

概念

在这里插入图片描述
链表大致示意图,通过一系类的链表将有效数据通过链式方式连接。

准备工作

  • vscode
    在这里插入图片描述

  • ubuntu

  • makefile
    makefile 如下

object = main.o slist.o
main : $(object)
	cc -o main $(object) 

%.o: %.c
	gcc -c $<
.PHONY : clean
clean : 
	rm *.o 
	rm main

第一版:一个错误的链表案例

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t *p_head = NULL;
    slist_node_t node1;
    slist_node_t *p_tmp;

    node1.date = 1;
    slist_add_end(p_head, &node1);
    p_tmp = p_head;

    while (p_tmp != NULL){ 
        printf("%d ", p_tmp->date); 
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node) 
{ 
    if (p_head == NULL){ 
        p_head = p_node; 
        p_node -> next = NULL; 
        } 
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

typedef struct _slist_node{
    int date;
    struct _slist_node *next;
}slist_node_t;


int slist_add_end(slist_node_t *p_head, slist_node_t *p_node); 
#endif // !_INCLUDE_H

第一版:修改完成后

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t *p_head = NULL;
    slist_node_t node1;
    slist_node_t *p_tmp;

    node1.date = 1;
    slist_add_end(&p_head, &node1);
    p_tmp = p_head;

    while (p_tmp != NULL){ 
        printf("%d ", p_tmp->date); 
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t **p_head, slist_node_t *p_node) 
{ 
    if (*p_head == NULL){ 
        *p_head = p_node; 
        p_node -> next = NULL; 
        } 
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

typedef struct _slist_node{
    int date;
    struct _slist_node *next;
}slist_node_t;


int slist_add_end(slist_node_t **p_head, slist_node_t *p_node); 
#endif // !_INCLUDE_H

在这里插入图片描述

第二版:再添加一个node值

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t *p_head = NULL;
    slist_node_t node1,node2,node3;
    slist_node_t *p_tmp;

    node1.date = 1;
    slist_add_end(&p_head, &node1);
    node2.date = 2;
    slist_add_end(&p_head, &node2);
    node3.date = 3;
    slist_add_end(&p_head, &node3);    

    p_tmp = p_head;

    while (p_tmp != NULL){ 
        printf("%d \r\n", p_tmp->date); 
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t **p_head, slist_node_t *p_node) 
{ 
    if (*p_head == NULL){ 
        *p_head = p_node; 
         p_node -> next = NULL; 
        }
    else{
        //先找到节点的尾部然后在尾部添加新节点
        slist_node_t *p_temp = *p_head;
        while (p_temp->next != NULL){
            p_temp = p_temp->next;
        }
        p_temp->next = p_node;
        p_node->next = NULL;
    } 
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

typedef struct _slist_node{
    int date;
    struct _slist_node *next;
}slist_node_t;


int slist_add_end(slist_node_t **p_head, slist_node_t *p_node);
#endif // !_INCLUDE_H

在这里插入图片描述

第三版:链表自带head

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {0,NULL};
    slist_node_t node1,node2,node3;
    slist_node_t *p_tmp;

    node1.date = 1;
    slist_add_end(&p_head, &node1);
    node2.date = 2;
    slist_add_end(&p_head, &node2);
    node3.date = 3;
    slist_add_end(&p_head, &node3);    

    p_tmp = &p_head;

    while (p_tmp != NULL){ 
        printf("%d \r\n", p_tmp->date); 
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

typedef struct _slist_node{
    int date;
    struct _slist_node *next;
}slist_node_t;


int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
#endif // !_INCLUDE_H

在这里插入图片描述

第四版:当date为结构体&数据量很大

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {{0},NULL};
    slist_node_t node1= {{"Chirs",'m',180.12,65.34},NULL};
    slist_node_t *p_tmp;

    slist_add_end(&p_head, &node1);

    p_tmp = &p_head;

    while (p_tmp != NULL){ 
        printf("name = %s \r\n", p_tmp->date.name); 
        printf("sex = %c \r\n", p_tmp->date.sex); 
        printf("height = %f \r\n", p_tmp->date.height); 
        printf("weight = %f \r\n", p_tmp->date.weight); 
        printf("-------------\r\n"); 
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef student_t element_type_t;

typedef struct _slist_node{
    element_type_t date;
    struct _slist_node *next;
}slist_node_t;


int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
#endif // !_INCLUDE_H

在这里插入图片描述

第五版:链表和数据分离

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {NULL};
    slist_init_t node1,node2,node3;
    slist_node_t *p_tmp;

    node1.data = 1;
    slist_add_end(&p_head, &node1.node);
    node2.data = 2;
    slist_add_end(&p_head, &node2.node);
    node3.data = 3;
    slist_add_end(&p_head, &node3.node);
    p_tmp = &p_head;

    while (p_tmp != NULL){ 
        printf("%d \r\n", ((slist_init_t *)p_tmp)->data);
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;

//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
#endif // !_INCLUDE_H

在这里插入图片描述

第五版:链表和数据分离(优化)使用函数接口(优化)

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {NULL};
    slist_init_t node1,node2,node3;
    slist_node_t *p_tmp;

    slist_init(&p_head);
    node1.data = 1;
    slist_add_end(&p_head, &node1.node);
    node2.data = 2;
    slist_add_end(&p_head, &node2.node);
    node3.data = 3;
    slist_add_end(&p_head, &node3.node);
    p_tmp = p_head.next;

    while (p_tmp != NULL){ 
        printf("%d \r\n", ((slist_init_t *)p_tmp)->data);
        p_tmp = p_tmp -> next; 
        }
}

slist.c

#include "slist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}

int slist_add_end(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;

    if((p_head == NULL)||(p_node == NULL)){
        return -1;
    }
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
int slist_init(slist_head_t *p_head);
#endif // !_INCLUDE_H

在这里插入图片描述

第六版:新增开始位置、结束位置、下个节点返回等接口函数

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {NULL};
    slist_init_t node1,node2,node3;
    

    slist_init(&p_head);
    node1.data = 1;
    slist_add_end(&p_head, &node1.node);
    node2.data = 2;
    slist_add_end(&p_head, &node2.node);
    node3.data = 3;
    slist_add_end(&p_head, &node3.node);

    slist_node_t *p_tmp = slist_begin_get(&p_head);
    slist_node_t *p_end = slist_end_get(&p_head);

    while (p_tmp != p_end){ 
        printf("%d \r\n", ((slist_init_t *)p_tmp)->data);
        p_tmp = slist_next_get(&p_head, p_tmp);
        }
}

slist.c

#include "slist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}

slist_node_t *slist_begin_get (slist_head_t *p_head)
{
    return slist_next_get(p_head,p_head);
}
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_pos)
{
    if(p_pos){
        return p_pos->next;
    }
    return NULL;
}
slist_node_t *slist_end_get (slist_head_t *p_head)
{
    return NULL;
}
int slist_add_end(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;

    if((p_head == NULL)||(p_node == NULL)){
        return -1;
    }
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);

slist_node_t *slist_begin_get (slist_head_t *p_head);//获取开始位置,第一个用户节点
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_pos); //获取某个节点的后一个位置
slist_node_t *slist_end_get (slist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int slist_init(slist_head_t *p_head);
#endif // !_INCLUDE_H

在这里插入图片描述

第七版:链表和数据处理分割、使用回调方法

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head = {NULL};
    slist_init_t node1,node2,node3;
    
    slist_init(&p_head);
    node1.data = 1;
    slist_add_end(&p_head, &node1.node);
    node2.data = 2;
    slist_add_end(&p_head, &node2.node);
    node3.data = 3;
    slist_add_end(&p_head, &node3.node);

    slist_foreach(&p_head,node_process_int,NULL);
}

slist.c

#include "slist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}

slist_node_t *slist_begin_get (slist_head_t *p_head)
{
    return slist_next_get(p_head,p_head);
}
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_pos)
{
    if(p_pos){
        return p_pos->next;
    }
    return NULL;
}
slist_node_t *slist_end_get (slist_head_t *p_head)
{
    return NULL;
}
int slist_add_end(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = p_head;
    int ret;
    if((p_head == NULL)||(p_node == NULL)){
        return -1;
    }
    while (p_temp->next != NULL){
        p_temp = p_temp->next;
    }
    p_temp->next = p_node;
    p_node->next = NULL;
    return 0; 
}

int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);

    while(p_start != p_end)
    {
        ret = pfn_node_process(p_arg, p_start);
        if(ret<0) return -1;
        p_start = slist_next_get(p_head,p_start);
    }
}

//***********************回调函数 节点处理函数****************************//

int node_process_int(void *p_arg, slist_node_t *p_node)
{
    printf("%d\r\n",((slist_init_t *)p_node)->data);
}

slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;

int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);

slist_node_t *slist_begin_get (slist_head_t *p_head);//获取开始位置,第一个用户节点
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_pos); //获取某个节点的后一个位置
slist_node_t *slist_end_get (slist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int slist_init(slist_head_t *p_head);

//****************************************************************
//对每个节点的使用
typedef int (*slist_node_process_t) (void *p_arg, slist_node_t *p_node);
//用户使用API
int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, slist_node_t *p_node);


#endif // !_INCLUDE_H

在这里插入图片描述

第八版:可用版-进一步抽象(静态方法)

main.c

#include "dlist.h"

int main(int argc, char **argv)
{
    slist_node_t p_head ;
    slist_init_t node1,node2,node3;
    
    slist_init(&p_head);
    node1.data = 1;
    slist_add_head(&p_head, &node1.node);
    node2.data = 2;
    slist_add_head(&p_head, &node2.node);
    node3.data = 3;
    slist_add_tail(&p_head, &node3.node);

    slist_foreach(&p_head,node_process_int,NULL);

    slist_del(&p_head, &node3.node);
    slist_foreach(&p_head,node_process_int,NULL);
}

slist.c

#include "dlist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}
slist_node_t *slist_begin_get (slist_head_t *p_head)
{
    return slist_next_get(p_head,p_head);
}
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_temp = p_head;
    while((p_temp!=NULL) && (p_temp->next!=p_current))
    {
        p_temp = p_temp->next;
    }
    return p_temp;
}
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current)
{
    if(p_current){
        return p_current->next;
    }
    return NULL;
}

slist_node_t *slist_tail_get (slist_head_t *p_head)
{
    return slist_prev_get(p_head, NULL);

}
slist_node_t *slist_end_get (slist_head_t *p_head)
{
    return NULL;
}


int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new)
{
    p_node_new->next= p_current->next;
    p_current->next = p_node_new;
    return 0;    
}

int slist_add_tail(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = slist_tail_get(p_head);
    return slist_add(p_head,p_temp,p_node);
}

int slist_add_head(slist_head_t *p_head, slist_node_t *p_node)
{
    return slist_add(p_head, p_head, p_node); // 添加头文件之后
}
int slist_del(slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_prev = slist_prev_get(p_head,p_current);
    if(p_prev){
        p_prev->next = p_current->next;
        p_current->next = NULL;
        return 0;
    }
    return -1;
}

int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);

    while(p_start != p_end)
    {
        ret = pfn_node_process(p_arg, p_start);
        if(ret<0) return -1;
        p_start = slist_next_get(p_head,p_start);
    }
    printf("------end--------\r\n");
    return 0;
}


//***********************回调函数 节点处理函数****************************//

int node_process_int(void *p_arg, slist_node_t *p_node)
{
    printf("%d\r\n",((slist_init_t *)p_node)->data);
    return 0;
}


slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;
int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new); //把new添加到当前之后
int slist_add_tail(slist_head_t *p_head, slist_node_t *p_node); 
int slist_add_head(slist_head_t *p_head, slist_node_t *p_node);

slist_node_t *slist_begin_get (slist_head_t *p_head);//获取开始位置,第一个用户节点
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current); //获取某个节点的后一个位置
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current);
slist_node_t *slist_tail_get (slist_head_t *p_head);
slist_node_t *slist_end_get (slist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int slist_init(slist_head_t *p_head);
int slist_del(slist_head_t *p_head, slist_node_t *p_current);//删除当前指针
//****************************************************************
//对每个节点的使用
typedef int (*slist_node_process_t) (void *p_arg, slist_node_t *p_node);
//用户使用API
int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, slist_node_t *p_node);


#endif // !_INCLUDE_H

在这里插入图片描述

第九版:可用版-进一步抽象(动态内存 malloc)修改节点添加函数

main.c

#include "dlist.h"

int main(int argc, char **argv)
{
    slist_head_t *p_head = (slist_head_t *)malloc(sizeof(slist_head_t)); 
    
    slist_init(p_head);

    my_list_add(p_head, 1);
    my_list_add(p_head, 2);
    my_list_add(p_head, 3);

    slist_foreach(p_head, node_process_int, NULL);

    my_list_del(p_head, 1);
    my_list_del(p_head, 2);
    my_list_del(p_head, 3);
    free(p_head);
}

slist.c

#include "dlist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}
slist_node_t *slist_begin_get (slist_head_t *p_head)
{
    return slist_next_get(p_head,p_head);
}
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_temp = p_head;
    while((p_temp!=NULL) && (p_temp->next!=p_current))
    {
        p_temp = p_temp->next;
    }
    return p_temp;
}
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current)
{
    if(p_current){
        return p_current->next;
    }
    return NULL;
}

slist_node_t *slist_tail_get (slist_head_t *p_head)
{
    return slist_prev_get(p_head, NULL);

}
slist_node_t *slist_end_get (slist_head_t *p_head)
{
    return NULL;
}

int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new)
{
    p_node_new->next= p_current->next;
    p_current->next = p_node_new;
    return 0;    
}

int slist_add_end(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = slist_tail_get(p_head);
    return slist_add(p_head,p_temp,p_node);
}

int slist_add_head(slist_head_t *p_head, slist_node_t *p_node)
{
    return slist_add(p_head, p_head, p_node); // 添加头文件之后
}
int slist_del(slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_prev = slist_prev_get(p_head,p_current);
    if(p_prev){
        p_prev->next = p_current->next;
        p_current->next = NULL;
        return 0;
    }
    return -1;
}

int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);

    while(p_start != p_end)
    {
        ret = pfn_node_process(p_arg, p_start);
        if(ret<0) return -1;
        p_start = slist_next_get(p_head,p_start);
    }
    return 0;
}


//***********************回调函数 节点处理函数****************************//

int node_process_int(void *p_arg, slist_node_t *p_node)
{
    printf("%d\r\n",((slist_init_t *)p_node)->data);
    return 0;
}
//动态内存分配 用户只要将数据data和头结点给函数就OK 
int my_list_add(slist_head_t *p_head, int data)
{
    slist_init_t *p_node = (slist_init_t *)malloc(sizeof(slist_init_t));
    if(p_node == NULL){
        printf("malloc data fail");
        return -1;
    }
    p_node->data = data;
    slist_add_head(p_head,&(p_node->node));
    return 0;
}
int my_list_del (slist_head_t *p_head, int data)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);
    while(p_start!=p_end)
    {
        if (((slist_init_t *)p_start)->data == data){
            printf("find the delet data = %d\r\n",((slist_init_t *)p_start)->data);
            slist_del(p_head,p_start);
            free(p_start);
            break;
        }
        p_start = slist_next_get(p_head,p_start);
    }
    slist_foreach(p_head,node_process_int,NULL);
    return 0;
}



slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"
#include <malloc.h>

//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;
//为什么要定义void * 节省了空间 链表只占4个字节 使用的时候强制转化即可
typedef int element_type_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;
int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new); //把new添加到当前之后
int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
int slist_add_head(slist_head_t *p_head, slist_node_t *p_node);

slist_node_t *slist_begin_get (slist_head_t *p_head);//获取开始位置,第一个用户节点
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current); //获取某个节点的后一个位置
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current);
slist_node_t *slist_tail_get (slist_head_t *p_head);
slist_node_t *slist_end_get (slist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int slist_init(slist_head_t *p_head);
int slist_del(slist_head_t *p_head, slist_node_t *p_current);//删除当前指针
//****************************************************************
//对每个节点的使用
typedef int (*slist_node_process_t) (void *p_arg, slist_node_t *p_node);
//-----------------------
int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, slist_node_t *p_node);


//-------------提供给用户使用 动态分配内存-----------------

int my_list_add(slist_head_t *p_head, int data);
int my_list_del (slist_head_t *p_head, int data);


#endif // !_INCLUDE_H

在这里插入图片描述

第10版:案例–数据处理使用学生结构

main.c

#include "slist.h"

int main(int argc, char **argv)
{
    slist_head_t p_head;
    slist_student_t s1, s2, s3, s4, s5;

    student_info_read(&s1.data); 
    student_info_read(&s2.data); 
    student_info_read(&s3.data); 
    student_info_read(&s4.data); 
    student_info_read(&s5.data);

    slist_add_head(&p_head, &s1.node); 
    slist_add_head(&p_head, &s2.node); 
    slist_add_head(&p_head, &s3.node); 
    slist_add_head(&p_head, &s4.node); 
    slist_add_head(&p_head, &s5.node);   

    slist_foreach(&p_head, list_process_student, NULL);   
}

slist.c

#include "slist.h"

int slist_init(slist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}
slist_node_t *slist_begin_get (slist_head_t *p_head)
{
    return slist_next_get(p_head,p_head);
}
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_temp = p_head;
    while((p_temp!=NULL) && (p_temp->next!=p_current))
    {
        p_temp = p_temp->next;
    }
    return p_temp;
}
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current)
{
    if(p_current){
        return p_current->next;
    }
    return NULL;
}

slist_node_t *slist_end_get (slist_head_t *p_head)
{
    return slist_prev_get(p_head, NULL);
//    return NULL;
}



int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new)
{
    p_node_new->next= p_current->next;
    p_current->next = p_node_new;
    return 0;    
}

int slist_add_end(slist_head_t *p_head, slist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    slist_node_t *p_temp = slist_end_get(p_head);
    return slist_add(p_head,p_temp,p_node);
}

int slist_add_head(slist_head_t *p_head, slist_node_t *p_node)
{
    return slist_add(p_head, p_head, p_node); // 添加头文件之后
}
int slist_del(slist_head_t *p_head, slist_node_t *p_current)
{
    slist_node_t *p_prev = slist_prev_get(p_head,p_current);
    if(p_prev){
        p_prev->next = p_current->next;
        p_current->next = NULL;
        return 0;
    }
    return -1;
}

int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);

    while(p_start != p_end)
    {
        ret = pfn_node_process(p_arg, p_start);
        if(ret<0) return -1;
        p_start = slist_next_get(p_head,p_start);
    }
    return 0;
}


//***********************回调函数 节点处理函数****************************//

int node_process_int(void *p_arg, slist_node_t *p_node)
{
    printf("%d\r\n",((slist_init_t *)p_node)->data);
    return 0;
}
int list_process_student(void *p_arg, slist_node_t *p_node) 
{ 
    student_t *p_s = &(((slist_student_t *)p_node)->data); 
    printf("%s : %c %.2f %.2f\n", p_s->name, p_s->sex, p_s->height, p_s->weight); 
    return 0; 
}
//动态内存分配 用户只要将数据data和头结点给函数就OK 
int my_list_add(slist_head_t *p_head, int data)
{
    slist_init_t *p_node = (slist_init_t *)malloc(sizeof(slist_init_t));
    if(p_node == NULL){
        printf("malloc data fail");
        return -1;
    }
    p_node->data = data;
    slist_add_head(p_head,&(p_node->node));
    return 0;
}
int my_list_del(slist_head_t *p_head, int data)
{
    slist_node_t *p_start;
    slist_node_t *p_end;
    p_start = slist_begin_get(p_head);
    p_end = slist_end_get(p_head);
    while(p_start!=p_end->next)
    {
        if (((slist_init_t *)p_start)->data == data){
            printf("find the delet data = %d\r\n",((slist_init_t *)p_start)->data);
            slist_del(p_head,p_start);
            free(p_start);
            break;
        }
        p_start = slist_next_get(p_head,p_start);
    }
    slist_foreach(p_head,node_process_int,NULL);
    return 0;
}

int student_info_read (student_t *p_student) 
{ 
    int i; 
 
    for (i = 0; i < 9; i++) { 
    p_student->name[i] = (rand() % ('z' - 'a')) + 'a'; 
    } 
    p_student->name[i]= '\0'; 
    p_student->sex = (rand() & 0x01) ? 'F' : 'M'; 
    p_student->height = (float)rand() / rand(); 
    p_student->weight = (float)rand() / rand(); 
    return 0; 
}


slist.h

#ifndef _INCLUDE_H
#define _INCLUDE_H
#include "stdio.h"
#include <malloc.h>
#include <stdlib.h>
//定义一个学生类型结构体
typedef struct _student{
    char name[10];
    char sex;
    float height,weight;
}student_t;

//单独链表
typedef struct _slist_node{
    struct _slist_node *next;
}slist_node_t;
typedef slist_node_t slist_head_t;
//定义链表和数据相互结合
//案例说明   数据处理为int  
//案例说明   数据处理为 student_t

typedef int element_type_t;
typedef student_t element_student_t;

//案例一 int 类型
typedef struct _slist_init{
    slist_node_t node;
    element_type_t data;
}slist_init_t;
//案例一 student 类型
typedef struct _slist_init_student{
    slist_node_t node;
    element_student_t data;
}slist_student_t;



int slist_add (slist_head_t *p_head, slist_node_t *p_current, slist_node_t *p_node_new); //把new添加到当前之后
int slist_add_end(slist_node_t *p_head, slist_node_t *p_node);
int slist_add_head(slist_head_t *p_head, slist_node_t *p_node);

slist_node_t *slist_begin_get (slist_head_t *p_head);//获取开始位置,第一个用户节点
slist_node_t *slist_next_get (slist_head_t *p_head, slist_node_t *p_current); //获取某个节点的后一个位置
slist_node_t *slist_prev_get (slist_head_t *p_head, slist_node_t *p_current);
slist_node_t *slist_end_get (slist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int slist_init(slist_head_t *p_head);
int slist_del(slist_head_t *p_head, slist_node_t *p_current);//删除当前指针
//****************************************************************
//对每个节点的使用
typedef int (*slist_node_process_t) (void *p_arg, slist_node_t *p_node);
//-----------------------
int slist_foreach(slist_head_t *p_head, slist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, slist_node_t *p_node);   //int 类型数据处理
int list_process_student(void *p_arg, slist_node_t *p_node);   //student 类型数据处理

//-------------提供给用户使用 动态分配内存-----------------

int my_list_add(slist_head_t *p_head, int data);
int my_list_del (slist_head_t *p_head, int data);

int student_info_read (student_t *p_student);



#endif // !_INCLUDE_H

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值