双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。本章中的双端链表为通用双端链表,其数据域类型为void *,可以接收任意类型的指针,达到通用的效果。首先我们来看dlist.h文件中结构体的声明和接口的声明:
//链表节点类型
typedef struct Dlist_node{
struct Dlist_node *prev; //前驱
struct Dlist_node *next; //后继
void *data; //可以接收任意类型指针(达到通用的效果)
}Dlist_node;
typedef struct Dlist{
struct Dlist_node *head; //头节点
struct Dlist_node *tail; //尾节点
int count; //数量
//data所指向内容的释放策略
void (*free)(void *ptr);
//data所指向内容的相等策略
Boolean (*match)(void *value1, void *value2);
//data所指向内容的拷贝策略
void *(*copy_node)(void *value);
}Dlist;
//通用链表的接口定义
Dlist *init_dlist(void) ; //双端链表的初始化
void destroy_dlist(Dlist **dlist); //双端链表的销毁
Boolean push_front(Dlist *dlist, void *value); //头插
Boolean push_back(Dlist *dlist, void *value) ; //尾插
Boolean pop_front(Dlist *dlist); //头删
Boolean pop_back(Dlist *dlist) ; //尾删
Dlist_node *find_node(Dlist *dlist, void *value); //节点查找
Boolean insert_prev(Dlist *dlist, Dlist_node *node,
void *value); //插入到指定节点前边
Boolean insert_next(Dlist *dlist, Dlist_node *node,
void *value); //插入到指定节点后边
Boolean remove_dlist_node(Dlist *dlist, Dlist_node *node); //删除指定节点
void print_dlist(Dlist *dlist, Print_func print) ; //链表的打印
Boolean get_front(Dlist *dlist, void **value); //得到头节点的data
Boolean get_tail(Dlist *dlist, void **value) ; //得到尾节点的data
int get_dlist_count(Dlist *dlist); //得到链表数量
typedef void (*Print_func)(void * value);
#endif
在dlist.h中同样声明了链表节点的结构体和链表控制信息的结构体,同时还使用了函数指针,函数指针可以使该指针指向同类型的函数(返回值类型和参数列表相同);Print_func为一种类型,其类型指向返回值为void,参数为void *的函数。
接下来我们在dlist.c中对于接口进行实现:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "dlist.h"
#include "tools.h"
Dlist *init_dlist(void) //双端链表的初始化
{
Dlist *dlist = (Dlist *)Malloc(sizeof(Dlist));
bzero(dlist,sizeof(Dlist));
return dlist;
}
void destroy_dlist(Dlist **dlist) //双端链表的销毁
{
if(dlist == NULL || *dlist == NULL){
return ;
}
//销毁步骤:
//1.先销毁链表节点(头删)
while((*dlist) -> count){
pop_front(*dlist);
}
//2.再销毁链表的控制信息
free(*dlist);
*dlist = NULL;
}
Boolean push_front(Dlist *dlist,void *value) //头插
{
Dlist_node * p_node = NULL;
if(dlist == NULL || value == NULL){
return FALSE;
}
p_node = (Dlist_node *)Malloc(sizeof(Dlist_node));
p_node ->data = value;
if(dlist ->count == ZERO){
dlist ->head = dlist ->tail = p_node;
}else{
p_node ->next = dlist ->head;
dlist ->head ->prev = p_node;
dlist ->head = p_node;
}
dlist ->count++;
return TRUE;
}
Boolean push_back(Dlist *dlist,void *value) //尾插
{
Dlist_node *p_node = NULL;
if(dlist == NULL || value == NULL){
return FALSE;
}
p_node = (Dlist_node *)Malloc(sizeof(Dlist_node));
p_node ->data = value;
p_node ->next = NULL;
if(dlist ->count == ZERO){
dlist ->head = dlist ->tail = p_node;
}else{
dlist ->tail ->next = p_node;
p_node ->prev = dlist ->tail;
dlist ->tail = p_node;
}
dlist ->count++;
return TRUE;
}
Boolean pop_front(Dlist *dlist) //头删
{
Dlist_node *p_node = NULL;
if(dlist == NULL || dlist ->count == ZERO){
return FALSE;
}
p_node = dlist ->head;
if(dlist ->count == ONE){
dlist ->head = dlist ->tail = NULL;
}else{
dlist ->head = dlist ->head ->next;
dlist ->head ->prev = NULL;
}
在dlist.c中包含了tools.h ,这是一个工具类头文件,其中包含了包裹函数Malloc和一些简单的函数:
tools.h :
<pre name="code" class="plain">#ifndef _TOOLS_H_
#define _TOOLS_H_
//定义布尔类型
#define TRUE (1)
#define FALSE (0)
typedef unsigned char Boolean;
//定义接口
void *Malloc(size_t size);
void print_int(void *value);
#endif
tools.c:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "tools.h"
4
5 void *Malloc(size_t size)
6 {
7 void *result = malloc(size);
8 if(result == NULL){
9 fprintf(stderr,"the memory is full!\n");
10 exit(1);
11 }
12 return result;
13 }
14
15 void print_int(void *value)
16 {
17 int *p = (int *)value;
18 printf("%5d",*p);
19 }
~ </strong></span>
测试程序:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "dlist.h"
4 #include "tools.h"
5
6 int main(int argc, char **argv)
7 {
8 Dlist *dlist = init_dlist(); //双端链表的初始化
9 int array[] = {12, 23, 34, 45, 56, 67, 78, 89};
10 int length = sizeof(array) / sizeof(array[0]);
11 int i = 0;
12
13 for(i = 0; i < length; ++i){
14 push_front(dlist, &array[i]);
15 }
16
17 print_dlist(dlist, print_int);//打印链表信息
18
19 destroy_dlist(&dlist); //链表的销毁
20 return 0;
21 }