数据结构4.进一步封装的双向链表

来源:互联网 发布:山东半岛城市群知乎 编辑:程序博客网 时间:2024/05/20 18:00

====
引言

    在前面,我们已经对数据结构中的双向链表进行了阐述,在这一节,我们将会对双向链表进行更深层次的封装。在C++的STL中。或者在java中,都会有一个概念叫做迭代器。迭代器提供对一个容器中的有范围的对象的访问。迭代器就如同一个指针。这一节我们可以迭代器封装链表使用户接触不到底层数据结构,保证安全访问。以及将我们常用到的函数封装在tools.h当中,使程序模块化,碎片化,冗余性低,便于提升和增加新功能。

一、双向链表定义
与上一节基本相同:
双向链表定义

#ifndef _DLIST_H_#define _DLIST_H_#include "iterator.h"                     // 这里我们增加了一个iterator迭代器的头文件#define TRUE      (1)#define FALSE     (0)#define ZERO      (0)#define ONLY_ONE  (1)typedef unsigned char Boolean ;           // 布尔类型typedef void (*Print_func)(void *value);  // 打印的函数指针void print_int(void *data);typedef struct Dlist_node{    struct Dlist_node *prev;    struct Dlist_node *next;              // 指向后一个节点    void              *data;}Dlist_node;typedef struct Dlist Dlist;//通用链表控制信息typedef struct Dlist{    struct Dlist_node *head;   //指向头结点    struct Dlist_node *tail;   //指向尾节点    int               count;    //这是一个指向某个需要被释放的数据域的函数指针    void (*free)(void *ptr);    //比较节点数据域 函数指针    Boolean (*match)(void *value1, void *value2);    //拷贝节点数据域 函数指针    void *(*copy_node)(void *value);    // 迭代器接口:    //指向链表头部    void *(*iter_head)(Iterator *iter, Dlist *dlist);    //指向链表尾部    void *(*iter_tail)(Iterator *iter, Dlist *dlist);    //指向前一个元素位置    void *(*iter_prev)(Iterator *iter, Dlist *dlist);    //指向后一个元素位置    void *(*iter_next)(Iterator *iter, Dlist *dlist);}Dlist;//1.双端链表的初始化    Dlist *init_dlist(void);//2.双端链表的销毁    void destroy_dlist(Dlist **dlist);//二重指针//3.头部插入    Boolean push_front(Dlist *dlist, void *data);//4.尾部插入    Boolean push_back(Dlist *dlist, void *data);//5.头部删除    Boolean pop_front(Dlist *dlist);//6.尾部删除    Boolean pop_back(Dlist *dlist);//7.插入到当前节点前    Boolean insert_prev(Dlist *dlist, Dlist_node *node, void *value); //8.插入到当前节点后    Boolean insert_next(Dlist *dlist, Dlist_node *node, void *value); //9.删除某个节点    Boolean remove_dlist_node(Dlist *dlist, Dlist_node *node);//10.显示双端链表信息    void show_dlist(Dlist *dlist, Print_func print);//11.得到第一个节点数据域    Boolean  get_front(Dlist *dlist, void **value);//12.得到最后一个节点数据域    Boolean  get_tail(Dlist *dlist, void **value);//13.得到链表节点数量    int get_dlist_count(Dlist *dlist);//14.得到第几个节点    Dlist_node *find_node(Dlist *dlist, int index);#endif

* 工具类接口定义 *

#ifndef _TOOLS_H_#define _TOOLS_H_#include <stdio.h>#include <stdlib.h>#include <string.h>//工具类接口void *Malloc(size_t size);void swap(void *a, void *b, int length);#endif

* 工具类接口实现 *

#include "tools.h"//工具类接口void *Malloc(size_t size){    void *result = malloc(size);    if(result == NULL)    {        fprintf(stderr, "the memory is full !\n");        exit(1);    }    return result;}void swap(void *a, void *b, int length){    void *temp = Malloc(length);    memcpy(temp, a, length);    memcpy(a, b, length);    memcpy(b, temp, length);    free(temp);}

二、迭代器的定义
collection 即 container

* 迭代器的定义 *

#ifndef _ITERATOR_H_#define _ITERATOR_H_typedef struct Iterator{    void   *ptr;        //指针 void* 通用指针    int   index;        //整型 index 指标 索引    int    size;        //整型 size 大小}Iterator;              //三个成员的一个结构体/* * 正向迭代器 * container(list、array、stack)容器 *///宏定义#define FOREACH(iter, container) \    for(container->iter_head(&(iter), container); \    (iter).ptr; \    container->iter_next(&(iter), container))#define foreach FOREACH#define FOREACH_REVERSE(iter, container) \    for(container->iter_tail(&(iter), container); \    (iter).ptr; \    container->iter_prev(&(iter), container))#define foreach_reverse FOREACH_REVERSE#endif

由于迭代器是在链表中使用,所以我们把迭代器操作实现一起放在了链表的实现文件里。
我们可以从定义中看到,我们定义的foreach是一个正向、在container中通过ptr指针指向下一个迭代的正向迭代方法。
foreach_reverse正好是从tail尾开始向前iter_prev反向的反向迭代。

三、双向链表的接口实现

#include "dlist.h"#include "tools.h"// 整型的打印函数void print_int(void *data){    printf("%d ",*(int *)data);}// 迭代器的接口函数指针定义static void *dlist_iter_head(Iterator *iter, Dlist *dlist);static void *dlist_iter_tail(Iterator *iter, Dlist *dlist);static void *dlist_iter_prev(Iterator *iter, Dlist *dlist);static void *dlist_iter_next(Iterator *iter, Dlist *dlist);//迭代器的接口函数指针实现//1.dlist的头迭代指针static void *dlist_iter_head(Iterator *iter, Dlist *dlist){    if(iter == NULL || dlist == NULL)    {        return NULL;    }    iter->index = 0;    iter->size = dlist->count;    //dlist的头节点    if(dlist->head->data == NULL || dlist->count == ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = dlist->head->data;    }    return iter->ptr;}//2.dlist的尾节点迭代static void *dlist_iter_tail(Iterator *iter, Dlist *dlist){    if(iter == NULL || dlist == NULL)    {        return NULL;    }    iter->index = dlist->count - 1;    iter->size = dlist->count;    //dlist的尾节点    if(dlist->tail->data == NULL || dlist->count == ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = dlist->tail->data;    }    return iter->ptr;}//3.dlist迭代前一个(函数指针)static void *dlist_iter_prev(Iterator *iter, Dlist *dlist){    if(iter == NULL || dlist == NULL)    {        return NULL;    }    iter->index --;    iter->size = dlist->count;    if(iter->index <= ZERO)    {        iter->ptr = NULL;    }    else    {        iter->ptr = find_node(dlist, iter->index)->data;    }    return iter->ptr;}//4.dlist迭代后一个(函数指针)static void *dlist_iter_next(Iterator *iter, Dlist *dlist){    if(iter == NULL || dlist == NULL)    {        return NULL;    }    iter->index ++;    iter->size = dlist->count;    if(iter->index >= iter->size)    {        iter->ptr = NULL;    }    else    {        iter->ptr = find_node(dlist, iter->index)->data;    }    return iter->ptr;}//创建一个节点Dlist_node *create_node(void);Dlist_node *create_node(void){    Dlist_node *node = (Dlist_node *)Malloc(sizeof(Dlist_node));    bzero(node, sizeof(Dlist_node));    return node;}//1.双端链表的初始化Dlist *init_dlist(void){    Dlist *dlist = (Dlist *)Malloc(sizeof(Dlist));    bzero(dlist, sizeof(Dlist));    //置函数指针    dlist->iter_head = dlist_iter_head;    dlist->iter_tail = dlist_iter_tail;    dlist->iter_prev = dlist_iter_prev;    dlist->iter_next = dlist_iter_next;    return dlist;}//2.双端链表的销毁void destroy_dlist(Dlist **dlist)//二重指针{    if(dlist == NULL || *dlist == NULL)    {        return;    }/*    while((*dlist)->head)        //(*)->    {         pop_back(*dlist);        //只要有头节点就尾删    }*/    Dlist_node *p_node = (*dlist)->head;    while((*dlist)->head != NULL)    {        (*dlist)->head = p_node->next;        if((*dlist)->free != NULL)        {            (*dlist)->free(p_node->data); //若我们有自己编写free函数,就用我们定义的free函数指针释放资源        }        free(p_node);        p_node = (*dlist)->head;    }    free(*dlist);    dlist = NULL;}//3.头部插入    //  case 1:    //     node    //       |    //   head tail     //    //  case 2:    //    node    //    //    //   node1==node2==node3    //      \         /    //       head|tailBoolean push_front(Dlist *dlist, void *data){    //创建新节点    Dlist_node *node = create_node();    node->data = data ;    if(dlist == NULL || data == NULL)    {        return FALSE;    }    if(dlist->count == ZERO)    {        dlist->tail = node;    //若dlist中没有元素则将dlist->tail也给这个节点    }    else    {        node->next = dlist->head;    //置node的next为头节点        dlist->head->prev = node;    //head的前一个置是node    }    dlist->head = node;    dlist->count ++;    return TRUE;}//4.尾部插入Boolean push_back(Dlist *dlist, void *data){    if(dlist == NULL || data == NULL)              {        return FALSE;    }    Dlist_node *node = create_node();              node->data = data ;    if(dlist->count == ZERO)    {        dlist->head = node;    }    else    {        node->prev = dlist->tail;        dlist->tail->next = node;    }    dlist->tail = node;    dlist->count ++;    return TRUE;                               }//5.头部删除Boolean pop_front(Dlist *dlist){    if(dlist == NULL || dlist->count == ZERO)    {        return FALSE;    }    Dlist_node *node = dlist->head;    if(dlist->count == ONLY_ONE)    {        dlist->head = dlist->tail = NULL;    }    else    {         dlist->head = node->next;        dlist->head->prev = NULL;    }/*    dlist->free(node);    node = NULL;*/    if(dlist->free != NULL)      //如果我们有相应的free函数    {        dlist->free(node->data); //调用自己的free函数    }    free(node);    dlist->count -- ;    return TRUE;}//6.尾部删除Boolean pop_back(Dlist *dlist){    if(dlist == NULL || dlist->count == ZERO)    {        return FALSE;    }    Dlist_node *node = dlist->tail;    if(dlist->count == ONLY_ONE)    {        dlist->head = dlist->tail = NULL;    }    else    {        dlist->tail = node->prev;        dlist->tail->next = NULL;    }    if(dlist->free != NULL)       //free函数指针    {        dlist->free(node->data);    }    free(node);    dlist->count -- ;    return TRUE;}//7.插入到当前节点前Boolean insert_prev(Dlist *dlist, Dlist_node *node, void *value){    Dlist_node *p_node = create_node();    p_node->data = value;    if(dlist == NULL || node == NULL )    {        return FALSE;    }    if(dlist->count == ONLY_ONE)    {        push_front(dlist, value);        return TRUE;    }    else                          //普通情况下    {        p_node->next = node;        p_node->prev = node->prev;        node->prev->next = p_node;        node->prev = p_node;        dlist->count++;    }    return TRUE;}//8.插入到当前节点后Boolean insert_next(Dlist *dlist, Dlist_node *node, void *value){    Dlist_node *p_node = create_node();    p_node->data = value;    if(dlist == NULL || node == NULL )    {        return FALSE;    }    if(dlist->count == ONLY_ONE)    {        push_back(dlist, value);        return TRUE;    }    else    {        p_node->next = node->next;        p_node->prev = node;        node->next->prev = p_node;        node->next = p_node;        dlist->count++;    }    return TRUE;}//9.删除某个节点Boolean remove_dlist_node(Dlist *dlist, Dlist_node *node){    if(dlist == NULL || node == NULL)    {        return FALSE;    }    if(node->next == NULL)    {        return pop_back(dlist);    }    else    {        Dlist_node *p_node = node->next;        node->data = p_node->data;        node->next = p_node->next;        p_node->next->prev = node;        if(dlist->free != NULL)        {            dlist->free(p_node->data);        }        free(p_node);        dlist->count -- ;    }    return TRUE;}//10.显示双端链表信息void show_dlist(Dlist *dlist, Print_func print){    Dlist_node *p_node = NULL;    if(dlist != NULL && dlist->count >0)    {        for(p_node = dlist->head; p_node; p_node = p_node->next)        {            print(p_node->data);   //这里是传入的参数指针        }        printf("\n");    }}//11.得到第一个节点数据域Boolean  get_front(Dlist *dlist, void **value)  //函数返回值为布尔类型,则可以通过参数保存需要得到的值。二重指针。{    if(dlist == NULL || dlist->count == ZERO)    {        return FALSE;    }    if(value != NULL)    {            *value = dlist->head->data;   //一级指针    }    return TRUE;}//12.得到最后一个节点数据域Boolean  get_tail(Dlist *dlist, void **value){    if(dlist == NULL || dlist->count == ZERO)    {        return FALSE;    }    if(value != NULL)    {            *value = dlist->tail->data;    }    return TRUE;}//13.得到链表节点数量int get_dlist_count(Dlist *dlist){    if(dlist == NULL)    {        return -1;      //返回值一般用-1表示出错;    }    else    {        return dlist->count;    }}//14.得到第几个节点Dlist_node *find_node(Dlist *dlist, int index){    int i = 0;    Dlist_node *p_node = NULL;    if(dlist == NULL || index > dlist->count || index < 0)  //判断条件    {        return NULL;    }    p_node = dlist->head;    while(i++ < index)    {        p_node = p_node->next;    }    return p_node;}

四、程序功能验证
main.c

#include <stdio.h>#include "dlist.h"/*void print_int(void *value);void print_int(void *value){    printf("%d ",*(int *)value); }*/int main(int argc, char **argv){    int i = 0;    int a[]={1,2,3,4,5};    void *value;    Iterator iter = {0};    Dlist *dlist = NULL;    dlist = init_dlist();    for(i=0; i< sizeof(a)/sizeof(a[0]);++i)    {        push_front(dlist, &a[i]);    }    show_dlist(dlist, print_int);    pop_front(dlist);    printf("---------foreach:\n");    //这里,我们就用到了迭代的方法,用我们定义的foreach对dlist这个容器进行迭代的输出。    foreach(iter, dlist)    {        print_int(iter.ptr);    }    printf("\n");    show_dlist(dlist, print_int);    for(i=0; i< sizeof(a)/sizeof(a[0]);++i)    {        push_back(dlist, &a[i]);    }    show_dlist(dlist, print_int);    pop_back(dlist);    show_dlist(dlist, print_int);    insert_prev(dlist, dlist->head->next->next, &a[4]);    show_dlist(dlist, print_int);    insert_next(dlist, dlist->head->next->next, &a[4]);    show_dlist(dlist, print_int);    remove_dlist_node(dlist, dlist->head->next->next->next);    show_dlist(dlist, print_int);    get_front(dlist, &value);    printf("\nfront:\n");    print_int(value);    get_tail(dlist, &value);    printf("\ntail:\n");    print_int(value);    printf("\n the length:\n");    printf("%d \n",get_dlist_count(dlist));    foreach(iter, dlist)    {        print_int(iter.ptr);    }    printf("\n");    destroy_dlist(&dlist);    return 0;}

编译运行结果

root@aemonair:i_dlist# cc.sh *.cCompiling ...-e CC      dlist.c main.c tools.c -g -lpthread-e         Completed .-e         Thu Jun 16 00:21:05 CST 2016

程序运行结果

root@aemonair:i_dlist# ./dlist 5 4 3 2 1 ---------foreach:4 3 2 1 4 3 2 1 4 3 2 1 1 2 3 4 5 4 3 2 1 1 2 3 4 4 3 5 2 1 1 2 3 4 4 3 5 5 2 1 1 2 3 4 4 3 5 2 1 1 2 3 4 front:4 tail:4 the length:9 4 3 5 2 1 1 2 3 4 

总结
这次,我们只是简单的对迭代器有了初步认识,并且进一步封装了双向链表。对于链表的基本操作并没有多大改进,只是着重强调了,对迭代器思想的认识。
同时,对双向链表的封装到了一定程度。我们可以实现通用的链表和接口,并用其实现其他的数据结构。

0 0
原创粉丝点击