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

双链程序

  • 循环双向链表
  • 头结点初始化
  • 添加节点
  • 添加节点在尾部
  • 添加节点在头部
  • 删除节点
  • 数据处理函数

添加一个节点图示+详解

在这里插入图片描述
添加一个节点最重要的是知道怎么添加,添加到谁的节点后面,在添加的过程中哪个节点的地址改变。
假设如下:

  • 地址改变说明:假设总共有两个节点A和C,这个时候B节点要加进来
    如下图所示 蓝色→地址有改变,共有4处,红色→代表值不变的地方

各节点详细说明:

  • A的p_next原本指向C的地址。更新后指向新节点B的地址。
  • A的p_prev因为存的是头节点,所以不变。
  • 新节点B的p_next指向C的地址
  • 新节点B的p_prev指向A的地址。
  • C节点next因为存的是头节点,所以不变。
  • C的p_prev指向新节点B的地址。

在这里插入图片描述
代码

int dlise_add(dlist_head_t *p_head,dlist_node_t *p_pos, dlist_node_t *p_newnode)
{
    if(p_head == NULL || p_pos == NULL || p_newnode == NULL)
    {
        return -1;
    }
    p_newnode->next = p_pos->next;
    p_newnode->prev = p_pos;
    
    p_pos->next = p_newnode;
    p_pos->next->prev =  p_newnode;
    return 0 ;
}

删除一个节点图示+详解

假设如下
这边共有3个节点A,B,C 然后将B删除,由图可知改变的值为蓝色→ 不变的值为红色→。

各节点详细说明:

  • A的p_next原本指向B的地址。更新后指向新节点C的地址。
  • A的p_prev因为存的是头节点,所以不变。
  • (被删除)节点B的p_next存的C的地址
  • (被删除)节点B的p_prev存的A的地址。
  • C节点next因为存的是头节点,所以不变。
  • C的p_prev原本指向节点B的地址更新后要指向A的地址。
    在这里插入图片描述

makefile

在这里插入图片描述

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

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

第一版:从单链表第八版修改成双向链表-初版

main.c

#include "dlist.h"

int main(int argc, char **argv)
{
    dlist_node_t p_head ;
    dlist_init_t node1,node2,node3;
    
    dlist_init(&p_head);
    node1.data = 1;
    dlist_add_head(&p_head, &node1.node);
    node2.data = 2;
    dlist_add_head(&p_head, &node2.node);
    node3.data = 3;
    dlist_add_tail(&p_head, &node3.node);

    dlist_foreach(&p_head,node_process_int,NULL);

    dlist_del(&p_head, &node3.node);
    dlist_foreach(&p_head,node_process_int,NULL);
}

dlist.c

#include "dlist.h"

int dlist_init(dlist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = NULL;
    return 0;
}
dlist_node_t *dlist_begin_get (dlist_head_t *p_head)
{
    return dlist_next_get(p_head,p_head);
}
dlist_node_t *dlist_prev_get (dlist_head_t *p_head, dlist_node_t *p_current)
{
    dlist_node_t *p_temp = p_head;
    while((p_temp!=NULL) && (p_temp->next!=p_current))
    {
        p_temp = p_temp->next;
    }
    return p_temp;
}
dlist_node_t *dlist_next_get (dlist_head_t *p_head, dlist_node_t *p_current)
{
    if(p_current){
        return p_current->next;
    }
    return NULL;
}

dlist_node_t *dlist_tail_get (dlist_head_t *p_head)
{
    return dlist_prev_get(p_head, NULL);

}
dlist_node_t *dlist_end_get (dlist_head_t *p_head)
{
    return NULL;
}


int dlist_add (dlist_head_t *p_head, dlist_node_t *p_current, dlist_node_t *p_node_new)
{
    p_node_new->next= p_current->next;
    p_current->next = p_node_new;
    return 0;    
}

int dlist_add_tail(dlist_head_t *p_head, dlist_node_t *p_node) 
{ 
    //先找到节点的尾部然后在尾部添加新节点
    dlist_node_t *p_temp = dlist_tail_get(p_head);
    return dlist_add(p_head,p_temp,p_node);
}

int dlist_add_head(dlist_head_t *p_head, dlist_node_t *p_node)
{
    return dlist_add(p_head, p_head, p_node); // 添加头文件之后
}
int dlist_del(dlist_head_t *p_head, dlist_node_t *p_current)
{
    dlist_node_t *p_prev = dlist_prev_get(p_head,p_current);
    if(p_prev){
        p_prev->next = p_current->next;
        p_current->next = NULL;
        return 0;
    }
    return -1;
}

int dlist_foreach(dlist_head_t *p_head, dlist_node_process_t pfn_node_process, void *p_arg)
{
    dlist_node_t *p_start;
    dlist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = dlist_begin_get(p_head);
    p_end = dlist_end_get(p_head);

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


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

int node_process_int(void *p_arg, dlist_node_t *p_node)
{
    printf("%d\r\n",((dlist_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 _dlist_node{
    struct _dlist_node *next;
    struct _dlist_node *prev;
}dlist_node_t;
typedef dlist_node_t dlist_head_t;
//定义链表和数据相互结合
typedef struct _dlist_init{
    dlist_node_t node;
    element_type_t data;
}dlist_init_t;
int dlist_add (dlist_head_t *p_head, dlist_node_t *p_current, dlist_node_t *p_node_new); //把new添加到当前之后
int dlist_add_tail(dlist_head_t *p_head, dlist_node_t *p_node); 
int dlist_add_head(dlist_head_t *p_head, dlist_node_t *p_node);

dlist_node_t *dlist_begin_get (dlist_head_t *p_head);//获取开始位置,第一个用户节点
dlist_node_t *dlist_next_get (dlist_head_t *p_head, dlist_node_t *p_current); //获取某个节点的后一个位置
dlist_node_t *dlist_prev_get (dlist_head_t *p_head, dlist_node_t *p_current);
dlist_node_t *dlist_tail_get (dlist_head_t *p_head);
dlist_node_t *dlist_end_get (dlist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int dlist_init(dlist_head_t *p_head);
int dlist_del(dlist_head_t *p_head, dlist_node_t *p_current);//删除当前指针
//****************************************************************
//对每个节点的使用
typedef int (*dlist_node_process_t) (void *p_arg, dlist_node_t *p_node);
//用户使用API
int dlist_foreach(dlist_head_t *p_head, dlist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, dlist_node_t *p_node);

#endif // !_INCLUDE_H

在这里插入图片描述

第二版(可用):实现双链增加删除显示

main.c

#include "dlist.h"

int main(int argc, char **argv)
{
    dlist_node_t p_head ;
    dlist_init_t node1,node2,node3;
    
    dlist_init(&p_head);
    node1.data = 1;
    dlist_add_tail(&p_head, &node1.node);
    node2.data = 2;
    dlist_add_tail(&p_head, &node2.node);
    node3.data = 3;
    dlist_add_tail(&p_head, &node3.node);

    dlist_foreach(&p_head,node_process_int,NULL);

}

dlist.c

#include "dlist.h"

int dlist_init(dlist_head_t *p_head)
{
    if(p_head == NULL){
        return -1;
    }
    p_head->next = p_head;
    p_head->prev = p_head;
    return 0;
}
dlist_node_t *dlist_begin_get (dlist_head_t *p_head)
{
    if(p_head){
        return p_head->next;
    }
    return NULL;
}
dlist_node_t *dlist_prev_get (dlist_head_t *p_head, dlist_node_t *p_current)
{
    if(p_current != NULL){
        return p_current->prev;
    }
    return NULL;
}
dlist_node_t *dlist_next_get (dlist_head_t *p_head, dlist_node_t *p_current)
{
    if(p_current){
        return p_current->next;
    }
    return NULL;
}

dlist_node_t *dlist_tail_get (dlist_head_t *p_head)
{
    if(p_head != NULL){
        return p_head->prev;
    }
    return NULL;
}
dlist_node_t *dlist_end_get (dlist_head_t *p_head)
{
        if(p_head != NULL){
        return p_head;
    }
    return NULL;
}

int dlist_add (dlist_head_t *p_head, dlist_node_t *p_current, dlist_node_t *p_node_new)
{
    if ((p_head == NULL) || (p_current == NULL) || (p_node_new == NULL)){ 
        return -1; 
    } 
    p_node_new->prev = p_current; 
    p_node_new->next = p_current->next; 
    p_current->next->prev = p_node_new; 
    p_current->next = p_node_new; 
    return 0;
}

int dlist_add_tail(dlist_head_t *p_head, dlist_node_t *p_node) 
{ 
    return dlist_add(p_head, p_head->prev, p_node);
}

int dlist_add_head(dlist_head_t *p_head, dlist_node_t *p_node)
{
    return dlist_add(p_head, p_head, p_node);
}
int dlist_del(dlist_head_t *p_head, dlist_node_t *p_current)
{
    if ((p_head == NULL) ||  (p_current == NULL)){ 
        return -1; 
    } 
    p_current->prev->next = p_current->next;
    p_current->next->prev = p_current->prev;

    p_current->next = NULL;
    p_current->prev = NULL;

    return 0;

}

int dlist_foreach(dlist_head_t *p_head, dlist_node_process_t pfn_node_process, void *p_arg)
{
    dlist_node_t *p_start;
    dlist_node_t *p_end;
    int ret;
    if((p_head == NULL)||(pfn_node_process == NULL))
        return -1;
    p_start = dlist_begin_get(p_head);
    p_end = dlist_end_get(p_head);

    while(p_start != p_end)
    {printf("--%d\r\n",((dlist_init_t *)p_start)->data);
        ret = pfn_node_process(p_arg, p_start);
        if(ret<0) return -1;
        p_start = dlist_next_get(p_head,p_start);
        
    }
    printf("------end--------\r\n");
    return 0;
}
//***********************回调函数 节点处理函数****************************//

int node_process_int(void *p_arg, dlist_node_t *p_node)
{
    printf("%d\r\n",((dlist_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 _dlist_node{
    struct _dlist_node *next;
    struct _dlist_node *prev;
}dlist_node_t;
typedef dlist_node_t dlist_head_t;
//定义链表和数据相互结合
typedef struct _dlist_init{
    dlist_node_t node;
    element_type_t data;
}dlist_init_t;
int dlist_add (dlist_head_t *p_head, dlist_node_t *p_current, dlist_node_t *p_node_new); //把new添加到当前之后
int dlist_add_tail(dlist_head_t *p_head, dlist_node_t *p_node); 
int dlist_add_head(dlist_head_t *p_head, dlist_node_t *p_node);

dlist_node_t *dlist_begin_get (dlist_head_t *p_head);//获取开始位置,第一个用户节点
dlist_node_t *dlist_next_get (dlist_head_t *p_head, dlist_node_t *p_current); //获取某个节点的后一个位置
dlist_node_t *dlist_prev_get (dlist_head_t *p_head, dlist_node_t *p_current);
dlist_node_t *dlist_tail_get (dlist_head_t *p_head);
dlist_node_t *dlist_end_get (dlist_head_t *p_head);//结束位置。尾节点下一个节点的位置

int dlist_init(dlist_head_t *p_head);
int dlist_del(dlist_head_t *p_head, dlist_node_t *p_current);//删除当前指针
//****************************************************************
//对每个节点的使用
typedef int (*dlist_node_process_t) (void *p_arg, dlist_node_t *p_node);
//用户使用API
int dlist_foreach(dlist_head_t *p_head, dlist_node_process_t pfn_node_process, void *p_arg);
int node_process_int(void *p_arg, dlist_node_t *p_node);

#endif // !_INCLUDE_H

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值