双向通用链表的学习
这儿是我的笔记,希望大家有好交流!!谢谢#__#
最近开始学习数据结构,于是从数据结构开始,由于比较笨,写这么个东西,加理解花了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天的学习!