数据结构之通用双端链表

    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。本章中的双端链表为通用双端链表,其数据域类型为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 }





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值