双向通用链表

双向通用链表的学习

这儿是我的笔记,希望大家有好交流!!谢谢#__#

最近开始学习数据结构,于是从数据结构开始,由于比较笨,写这么个东西,加理解花了2天的时间(想哭,感觉后面更加艰难,非科班自学很痛苦)。
首先是头文件zhizhenxingtongyongshuangxianglist.h
#ifndef _ZHIZHENXINGTONGYONGSHUANGXIANGLIST_H_
#define _ZHIZHENXINGTONGYONGSHUANGXIANGLIST_H_
#include<stdlib.h>
typedef enum
{
    false = 0,
    true,
}bool;
typedef  (*OPERATE)();
struct node;
typedef struct node NODE;
typedef struct node* NODE_T;


struct dList;
typedef struct dlist DList;
typedef struct dlist* DList_T;

DList_T DList_InitToEmpty(DList_T DL,OPERATE op1,OPERATE op2);
bool DList_DeleteAll(DList_T DL,OPERATE op);//属于回调接口,因为链表装的都是指针,所以主要的内存管理由用户操作
void DList_For_Each(DList_T DL, OPERATE op,void* sxw );

bool DList_InsertNext(DList_T DL, NODE_T pos, const void* data);
bool DList_InsertPre(DList_T DL, NODE_T pos, const void* data);
bool DList_DeleteOne(DList_T DL,NODE_T pos,OPERATE op, void** data);///////////////////////
NODE_T DList_FindNode(DList_T DL,OPERATE visit,void* data);
void* DList_GetNodeValue(const NODE_T pos);
//属于私人的
NODE_T DList_GetNodeNext(const NODE_T pos);
NODE_T DList_GetNodePre(const NODE_T pos);
NODE_T DList_Tail(DList_T DL);
NODE_T DList_Head(DList_T DL);
bool DList_SetDelete(DList_T DL,OPERATE op);
bool DList_SetCompare(DList_T DL,OPERATE op);

#endif 

这里考虑了数据隐藏所以将struct node和struct dlist都放在.c文件中定义,这里只做声明并向外展示。
考虑到用C来实现类似c++模板的功能(使得链表不在乎数据类型)所以之后的node定义如下
struct node
{
void
data;
struct node
prev;
struct node* next;
};data是一个空类型的指针,因为可以接受任意类型的指针。
对于dlist的定义如下:
struct dlist
{
struct node
head;//指针型的
struct node
tail;
int length;
OPERATE my_delete;//函数指针
OPERATE my_compare;//函数指针
};

my_delete,my_compare是两个函数指针变量,OPERATE 是函数指针的类型,这两个也是为了考虑通用型设计的,即当A用户(其操作的数据fa的方式是int,比如按int类型的键值找某个节点)用这个数据结构时,可以自定义比较int的函数,然后传给链表,以后链表以用户给的方式做相应的键值比较(这个可以联想到函数回调法,在这次设计中有多次用到),当B用户相以字符串的方式找元素,则可以自定义一个字符串的比较,然后传给链表,让其进行回调;
delete也是,当data指向的数据(用户)是由动态分配得到的,则在删除链表的时候,在删除node节点前,需要将data指向的内存释放,鉴于哪里开辟的内存哪里释放的原则,这个内存应该由用户释放,所以需要一个二级指针和回调函数。

接口的功能:
1:DList_T DList_InitToEmpty(DList_T DL,OPERATE op1,OPERATE op2);
初始化一个空链表,再使用一个链表前,一定要先使用这个函数,op1,op2使用户的函数,关于用户自定义比较的方式和用户自定义释放内存的函数。
2:bool DList_DeleteAll(DList_T DL,OPERATE op);
删除整个链表,当op=NULL,说明data指向的元素,不含有由动态分配而来的变量;
3:void DList_For_Each(DList_T DL, OPERATE op,void sxw );*
为每个元素执行相关操作,sxw是回调函数的上下文
4:bool DList_InsertNext(DList_T DL, NODE_T pos, const void data);*
在链表的指定元素后面插入一个元素
5:bool DList_InsertPre(DList_T DL, NODE_T pos, const void data);*
在链表的指定元素前面插入一个元素
6:bool DList_DeleteOne(DList_T DL,NODE_T pos,OPERATE op, void data);**
删除链表中被指定的元素,并将这个元素的数据域保存传回用户层,由用户层负责
7:NODE_T DList_FindNode(DList_T DL,OPERATE visit,void data);*
查找指定的元素
8:void DList_GetNodeValue(const NODE_T pos);*
获取某个节点的值域

以下代码可以定义为模块内函数,放在.c中static描述(偷个懒,这一步没做了,所以放在头文件中了,也可以弄成宏定义)
9:NODE_T DList_GetNodeNext(const NODE_T pos);
获取指定节点的下一个节点:
10:NODE_T DList_GetNodePre(const NODE_T pos);
获取指定节点的前一个节点:
11:NODE_T DList_Tail(DList_T DL);
获取尾节点
12:NODE_T DList_Head(DList_T DL);
获取头结点
13bool DList_SetDelete(DList_T DL,OPERATE op);
设置链表的函数指针变量
14bool DList_SetCompare(DList_T DL,OPERATE op);
设置链表的函数指针变量

实现代码如下:

#include "zhizhenxingtongyongshuangxianglist.h"
//释放node只是释放了存放包括data的存储区,data指向的地方还没有被释放
struct node
{
    void* data;
    struct node* prev;
    struct node* next;
};//单个元素

//这也是一种方式,而且更好
struct dlist
{
    struct node* head;//指针型的
    struct node* tail;
    int length;
    OPERATE my_delete;//函数指针
    OPERATE my_compare;//函数指针

};//链表的定义


DList_T DList_InitToEmpty(DList_T DL,OPERATE op1,OPERATE op2)
{
    DList_T dl = DL;
    if((dl=(DList_T)malloc(sizeof(DList))) != NULL )
    {
        dl->head = NULL;
        dl->tail = NULL;
        dl->length = 0;
        dl->my_delete = op1;
        dl->my_compare = op2;
        return dl;
    }
    return NULL;
}
bool DList_DeleteAll(DList_T DL,OPERATE op)//属于回调接口,因为链表装的都是指针,所以主要的内存管理由用户操作
{
    DList_T dl = DL;
    void *data = NULL;
    while(DList_Length(dl) != 0)
    {
        DList_DeleteOne(dl,DList_Tail(dl),op,(void**)&data);
    }
    free(dl);//这一句一定要加
}
bool DList_DeleteOne(DList_T DL,NODE_T pos,OPERATE op, void** data)
{
    DList_T dl = DL;
    if(DList_Length(dl) == 0 || pos == NULL)
    {
        return false;
    }
    *data = pos->data; //先保存,如果不用二级指针的话,则被调用者是不知道

     if(pos == dl->head)//看看是不是头结点
    {
        dl->head = pos->next;
        if(dl->head == NULL) dl->tail = NULL;
        else    dl->head->prev = NULL;
    }
    else
    {
        pos->prev->next = pos->next;
        if(pos->next == NULL) dl->tail = pos->prev;
        else pos->next->prev = pos->prev;
    }
    free(pos);
    pos = NULL;
    dl->length--;
    if(op != NULL)
    {
         DList_SetDelete(dl,op);
         dl->my_delete(data);                  
    }
    return true;
}
void DList_For_Each(DList_T DL, OPERATE op,void* sxw )
{
    DList_T dl= DL;
    NODE_T tmp = dl->head;
    int len = DList_Length(dl);
    while(len)
    {
        op(sxw,tmp->data);
        len--;
        tmp = DList_GetNodeNext(tmp);
    }
}
bool DList_InsertNext(DList_T DL, NODE_T pos, const void* data)
{
    NODE_T newnode = NULL;
    DList_T dl= DL;
    if((newnode=(NODE_T)malloc(sizeof(NODE)))!= NULL)
    {
        newnode->data = data;
        newnode->prev = NULL;
        newnode->next = NULL;
        if(dl->length ==0)
        {
            dl->head = newnode;
            dl->tail = newnode;//后面两个很关键
        }
        else
        {
            newnode->next = pos->next;
            newnode->prev = pos;
            if(pos->next == NULL)
            {
                dl->tail = newnode;
            }
            else
            {
                pos->next->prev = newnode;
            }
            pos->next = newnode;
        }
        dl->length++;
    }
    return true;
}
bool DList_InsertPre(DList_T DL, NODE_T pos, const void* data)
{
    DList_T dl =DL;
    NODE_T newnode = NULL;
    if((newnode=(NODE_T)malloc(sizeof(NODE)))!= NULL)
    {
        newnode->prev = NULL;
        newnode->next = NULL;
        newnode->data = data;

        if(DList_Length(dl)==0)
        {
            dl->head = newnode;
            dl->tail = newnode;
        }
        else
         {
             newnode->next = pos;
             newnode->prev = pos->prev;
             if(pos->prev == NULL)
             {
                 dl->head = newnode;
             }
             else
             {
                 pos->prev->next = newnode;
             }
             pos->prev = newnode;
         }
         dl->length++;
    }
    return true;

}
NODE_T DList_FindNode(DList_T DL,OPERATE visit ,void* data)
{
     DList_T dl =DL;
    int len = DList_Length(dl);
    NODE_T fnd = DList_Head(dl);
    DList_SetCompare(dl,visit);
    while(len)
    {
       // bool t = false;
        //t = visit(fnd->data,data);
        if(dl->my_compare(fnd->data,data)) return fnd;
        len--;
        fnd = DList_GetNodeNext(fnd);
    }
    return NULL;
}
void* DList_GetNodeValue(const NODE_T pos)
{
    return pos->data;
}
int DList_Length(DList_T DL)
{
    return DL->length;
}
 NODE_T DList_Head(DList_T DL)
{
    return DL->head;
}
 NODE_T DList_Tail(DList_T DL)
{
    return DL->tail;
}
 NODE_T DList_GetNodeNext(const NODE_T pos)
{
    return pos->next;
}
 NODE_T DList_GetNodePre(const NODE_T pos)
{
    return pos->prev;
}
 bool DList_SetDelete(DList_T DL, OPERATE op)
{
    DList_T dl = DL;
    dl->my_delete = op;
    return true;
}
 bool DList_SetCompare(DList_T DL, OPERATE op)
{
    DList_T dl = DL;
    dl->my_compare = op;
    return true;
}

测试文件放在main.c

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<memory.h>
#include "zhizhenxingtongyongshuangxianglist.h"
typedef struct
{
    int sco;
}STU,*STU_T;
typedef struct
{
    char *name;
}PERSON,*PERSON_T;
void print(int* sxw,STU_T stu);
bool compare(STU_T stu,STU_T fnd);

void print1(int* sxw,PERSON_T per);
bool compare1(PERSON_T per,PERSON_T fnd);
void my_free(PERSON_T per);
int main()
{
    DList_T dlist = DList_InitToEmpty(dlist,NULL,NULL);
    DList_T dlist1 =DList_InitToEmpty(dlist1,NULL,NULL);
    STU stu[3] = {{100},{200},{300}};
    char* nm[3] ={"yyb","txw","wyc"};
    PERSON person[3];
    NODE_T tmp = NULL;
    STU_T t=NULL;
    int i = 0;
    void* data = NULL;
    DList_InsertNext(dlist,DList_Tail(dlist),&stu[0]);
    DList_InsertNext(dlist,DList_Tail(dlist),&stu[1]);
    DList_InsertNext(dlist,DList_Tail(dlist),&stu[2]);

    printf("%d\n",DList_Length(dlist));

    printf("\n原始的链表内容是:\n");
    DList_For_Each(dlist,print,NULL);

    tmp=DList_FindNode(dlist,compare,&stu[1]);
    printf("找到一个元素\n");
    print(NULL,(STU_T)DList_GetNodeValue(tmp));

    printf("\n删除一个元素后,链表内容\n");
    DList_DeleteOne(dlist,DList_FindNode(dlist,compare,&stu[1]),NULL,(void**)&data);
    DList_For_Each(dlist,print,NULL);

    printf("\n将元素插回去\n");
    DList_InsertPre(dlist,DList_FindNode(dlist,compare,&stu[2]),&stu[1]);
    DList_InsertNext(dlist,DList_FindNode(dlist,compare,&stu[0]),&stu[1]);
    DList_For_Each(dlist,print,NULL);

    DList_DeleteAll(dlist,NULL);

    printf("\n********现在开始第二张表,表中的数据带有动态分配的********\n");
    for(i = 0;i<=2;i++)
    {
        person[i].name = (char*)malloc(5*sizeof(char));
        memset(person[i].name,0,5);
        memcpy(person[i].name,nm[i],strlen(nm[i]));
        printf("%s\n",person[i].name);
        DList_InsertNext(dlist1,DList_Tail(dlist1),&person[i]);
    }
    printf("\n第二张原始的链表内容是:\n");
    DList_For_Each(dlist1,print1,NULL);

    printf("\n删除一个元素后,链表内容\n");
    DList_DeleteOne(dlist1,DList_FindNode(dlist1,compare1,&person[1]),my_free,(void**)&data);
    DList_For_Each(dlist1,print1,NULL);

    DList_DeleteAll(dlist1,my_free);
    printf("\n删除所有元素后,链表内容\n");
    DList_For_Each(dlist1,print1,NULL);
    return 0;
}
void print(int* sxw,STU_T stu)
{
    printf("%d\t",stu->sco);
}
void print1(int* sxw,PERSON_T per)
{
    printf("%s\t",per->name);
}
bool compare(STU_T stu,STU_T fnd)
{
    if(stu->sco == fnd->sco) return true;
    return false;
}
bool compare1(PERSON_T per,PERSON_T fnd)
{
    if(strcmp(per->name,fnd->name)==0) return true;
    return false;
}
void my_free(PERSON_T per)//用户的free
{
    free(per->name);
    per->name = NULL;
}

至此,完成了2天的学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值