双链程序
- 循环双向链表
- 头结点初始化
- 添加节点
- 添加节点在尾部
- 添加节点在头部
- 删除节点
- 数据处理函数
添加一个节点图示+详解
添加一个节点最重要的是知道怎么添加,添加到谁的节点后面,在添加的过程中哪个节点的地址改变。
假设如下:
- 地址改变说明:假设总共有两个节点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