目录
一、双向链表数据结构
struct double_list_node
{
struct double_list_node *prev; /* prev node*/
struct double_list_node *next; /* next node*/
void *value; /* node value */
};
struct double_list
{
struct double_list_node *head; /* list head */
struct double_list_node *tail; /* list head */
unsigned int len; /* node num */
};
双向链表的每一个节点都有一个前驱节点和后继节点,可根据当前节点获取到它的前后节点节点查找、插入效率比单向链表效率高。在使用时,需要先动态创建一个头节点 list,并将 list->head 和 list->tail 指向链表中的第一个节点,同时记录链表中节点数目
二、双向链表增删改查函数声明
extern struct double_list* double_list_creat(void);
extern int double_list_add_node_head(struct double_list *list, void *value);
extern int double_list_add_node_tail(struct double_list *list, void *value);
extern int double_list_insert_node (struct double_list *list, struct double_list_node *pos_node, void *value, char dir);
extern int double_list_node_del (struct double_list *list, struct double_list_node *del_node, char val_isdyn);
extern int double_list_node_empty (struct double_list *list, char val_isdyn);
extern int double_list_destroy (struct double_list *list, char val_isdyn);
extern void double_list_test(void);
三、创建链表
1、链表头动态创建
/**
* dynamically create a double list.
*
* @return NULL:malloc fail
* !NULL:success
*/
struct double_list* double_list_creat(void)
{
struct double_list *list = NULL;
list = DOUBLE_LIST_MALLOC(sizeof(*list));
if (list == NULL)
return NULL;
list->head = NULL;
list->tail = NULL;
list->len = 0;
return list;
}
2、链表头静态创建
/**
* init a double list.
*
* @param list: double list
* @return -1:list is null
* 0:success
*/
int double_list_init(struct double_list *list)
{
if (list == NULL)
return -1;
list->head = NULL;
list->tail = NULL;
list->len = 0;
return 0;
}
四、节点添加
1、 头插法
每次添加节点都是在头节点前面添加,node为最新添加的节点,添加过程
① 动态创建一个新的节点node
② node->next = list->head
③ list->head = node
/**
* insert a value to the double list forward.
*
* @param list: double list
* @param value: data
* @return -1:list is null or value is null
* -2:node malloc fail
* 0:success
*/
int double_list_add_node_head(struct double_list *list, void *value)
{
struct double_list_node *node = NULL;
if (list == NULL || value == NULL)
return -1;
node = DOUBLE_LIST_MALLOC(sizeof(*node));
if (node == NULL)
return -2;
/* add node */
node->value = value;
node->prev = NULL;
node->next = list->head;
/* move list tail to end node */
if (list->tail == NULL)
{
list->tail = node;
}
/* move list head to first node */
list->head = node;
list->len++;
return 0;
}
2、 尾插法
每次添加节点都是在tail指向节点后面添加,头节点始终不动指向链表第一个节点,node为最新添加的节点,需要注意是否为第一个节点,添加过程为:
① 动态创建一个新的节点node,node->prev = NULL node->next = NULL
② 在list->tail后面添加node
/**
* insert a value to the double list backwards.
*
* @param list: double list
* @param value: data
* @return -1:list is null or value is null
* -2:node malloc fail
* 0:success
*/
int double_list_add_node_tail(struct double_list *list, void *value)
{
struct double_list_node *node = NULL;
if (list == NULL || value == NULL)
return -1;
node = DOUBLE_LIST_MALLOC(sizeof(*node));
if (node == NULL)
return -2;
node->value = value;
node->next = NULL;
node->prev = NULL;
/* first node */
if (list->head == NULL && list->tail == NULL && list->len == 0)
{
list->head = node;
list->tail = node;
}
/* not the first node */
else
{
node->prev = list->tail;
list->tail->next = node;
list->tail = node;
}
list->len++;
return 0;
}
3、 位置节点前或后插入
/**
* Insert a new node before or after a node.
*
* @param list: double list
* @param pos_node: insert node postion
* @param value: data
* @param dir: 1 before, 2 after
* @return -1:list is null or value is null
* -2:node malloc fail
* -3:pos node is not in the list
* 0:success
*/
int double_list_insert_node(struct double_list *list, struct double_list_node *pos_node, void *value, char dir)
{
struct double_list_node *node = NULL;
struct double_list_node *temp = NULL;
unsigned int i = 0;
if (list == NULL || pos_node == NULL || value == NULL)
return -1;
node = DOUBLE_LIST_MALLOC(sizeof(*node));
if (node == NULL)
return -2;
for (i=0,temp=list->head; i < list->len; i++,temp=temp->next)
{
if (temp == pos_node)
break;
}
/* delete node is not in the list */
if (i == list->len)
return -3;
node->value = value;
node->next = NULL;
node->prev = NULL;
/* Insert before the node*/
if (dir == 1)
{
/* before the head */
if (pos_node == list->head)
{
pos_node->prev = node;
node->next = pos_node;
list->head = node;
}
else
{
pos_node->prev->next = node;
node->prev = pos_node->prev;
node->next = pos_node;
pos_node->prev = node;
}
}
/* insert after the node */
else if (dir == 2)
{
if (pos_node == list->tail)
{
pos_node->next = node;
node->prev = pos_node;
list->tail = node;
}
else
{
node->next = pos_node->next;
pos_node->next->prev = node;
pos_node->next = node;
node->prev = pos_node;
}
}
list->len++;
return 0;
}
注意:在位置节点前插入中位置节点为链表头节点,则需要向前移动头节点指向新插入节点。位置节点后插入中位置节点为链表为节点,则需要向后移动尾节点,指向新插入的节点。位置节点后插入中位置节点为链表尾节点,则需要向后移动尾节点,指向新插入的节点
五、节点删除
/**
* delete a node.
* @note The value space may be static, so the val_isdyn identification is needed
* to tell if the value space needs to be released manually
* @param list: double list
* @param val_isdyn: 1 = value is dynamic apply
* @return -1:list is null
* -3:delete node is not in the list
* 0:success
*/
int double_list_node_del(struct double_list *list, struct double_list_node *del_node, char val_isdyn)
{
struct double_list_node *temp = NULL;
unsigned int i = 0;
if (list == NULL || del_node == NULL)
return -1;
for (i=0,temp=list->head; i < list->len; i++,temp=temp->next)
{
if (temp == del_node)
break;
}
/* delete node is not in the list */
if (i == list->len)
return -3;
/* delete node is the head node */
if (del_node == list->head)
{
del_node->next->prev = NULL;
list->head = del_node->next;
}
/* delete node is the tail node */
else if (del_node == list->tail)
{
del_node->prev->next = NULL;
list->tail = del_node->prev;
}
else
{
del_node->prev->next = del_node->next;
del_node->next->prev = del_node->prev;
}
del_node->next = NULL;
del_node->prev = NULL;
if (val_isdyn)
{
DOUBLE_LIST_FREE(del_node->value);
}
DOUBLE_LIST_FREE(del_node);
del_node = NULL;
list->len--;
return 0;
}
注意:如果要删除节点为链表头节点或是尾节点,则需要向后移动头结点或是向前移动尾节点。警惕指针丢失和内存泄漏,然后再释放del节点空间
六、链表清空
/**
* empty the double list all node.
* @note The value space may be static, so the val_isdyn identification is needed
* to tell if the value space needs to be released manually
* @param list: double list
* @param val_isdyn: 1 = value is dynamic apply
* @return -1:list is null
* 0:success
*/
int double_list_node_empty(struct double_list *list, char val_isdyn)
{
struct double_list_node *node = NULL;
if (list == NULL)
return -1;
while (list->head != NULL && list->len > 0)
{
/* move list head node to head next node */
node = list->head;
list->head = list->head->next;
list->len--;
if (val_isdyn)
{
DOUBLE_LIST_FREE(node->value);
node->value = NULL;
}
/* free space */
node->next = NULL;
node->prev = NULL;
DOUBLE_LIST_FREE(node);
node = NULL;
}
list->tail = NULL;
return 0;
}
七、链表销毁
/**
* destroy the double list.
* @note The list node needs to be empty before destroy list
* @param list: double list
* @return -1:list is null
* 0:success
*/
int double_list_destroy(struct double_list *list, char val_isdyn)
{
if (double_list_node_empty(list, val_isdyn) != 0)
return -1;
list->head = NULL;
list->tail = NULL;
DOUBLE_LIST_FREE(list);
list = NULL;
return 0;
}
八、验证程序
struct double_list *double_list;
struct double_list_node *double_node;
int double_test_w[] = {10, 20, 30, 40, 50};
int double_test_r[15] = {0};
void double_list_test(void)
{
int i = 0;
double_list = double_list_creat();
/* head insert */
double_list_add_node_head(double_list, (void*)&double_test_w[0]);
double_list_add_node_head(double_list, (void*)&double_test_w[1]);
double_list_add_node_head(double_list, (void*)&double_test_w[2]);
double_list_add_node_head(double_list, (void*)&double_test_w[3]);
double_list_add_node_head(double_list, (void*)&double_test_w[4]);
double_node = double_list->head;
for (i=0; i<double_list->len; i++)
{
double_test_r[i] = *(int*)double_node->value;//50 40 30 20 10
double_node = double_node->next;
}
/* tail insert */
double_list_node_empty(double_list, 0);
double_list_add_node_tail(double_list, (void*)&double_test_w[0]);
double_list_add_node_tail(double_list, (void*)&double_test_w[1]);
double_list_add_node_tail(double_list, (void*)&double_test_w[2]);
double_list_add_node_tail(double_list, (void*)&double_test_w[3]);
double_list_add_node_tail(double_list, (void*)&double_test_w[4]);
double_node = double_list->head;
for (i=0; i<double_list->len; i++)
{
double_test_r[i] = *(int*)double_node->value;//10 20 30 40 50
double_node = double_node->next;
}
/* pos insert */
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[0], 1);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[1], 1);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[2], 1);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[3], 1);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[4], 1);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[0], 2);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[1], 2);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[2], 2);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[3], 2);
double_list_insert_node(double_list, double_list->head, (void*)&double_test_w[4], 2);
double_node = double_list->head;
for (i=0; i<double_list->len; i++)
{
double_test_r[i] = *(int*)double_node->value;
double_node = double_node->next;
}
/* destroy list */
double_list_destroy(double_list, 0);
}