最近在CSDN上看到了absurd大神的几篇关于系统程序员成长计划的的博文
里面提到了关于通用链表实现的思想,虽然数据结构学的还行,但是真的没写过通用的链表,对封装的认识比较浅显!
于是乎决定实现一下,真正开始写才发现,对我这么个眼高手低的菜鸟来说挺有难度的。写篇博文记录下。
整体实现的主题思想还是absurd大神博文中的两个重要思想:
1, 链表数据段存指针void*
2 采用回调函数来使的链表的基本函数更有通用性
贴代码:
links.h
- #ifndef LINKS_H_
- #define LINKS_H_
- #include <malloc.h>
- #include <stdbool.h>
- #include <stdio.h>
- #define LEN_LIST sizeof(DListNode)
- typedef bool (*DListDataPrintFunc)(void* data); //打印链表的回调函数接口
- typedef bool (*DListVistFunc)(void* data, void* ctx); //遍利链表的回掉函数接口
- typedef bool (*DListDataAssign)(void* data, void* ctx);
- typedef struct _DListNode{
- struct _DListNode* prev;
- struct _DListNode* next;
- void * data;
- //int data;
- }DListNode,*ptrDListNode;
- typedef struct {
- ptrDListNode head,tail;
- int len;
- }LinkList,*ptrLinkList;
- //开辟一个节点 返回指向该节点的指针
- ptrDListNode CreateNode();
- //释放一个节点内存 返回空指针值
- ptrDListNode DestroyDListNode(ptrDListNode e);
- //初始化一个链表头节点
- ptrLinkList InitList();
- //销毁一个链表头节点 以及链表内所有元素 返回NULL
- ptrLinkList DestroyLinkList(ptrLinkList L);
- //为链表的节点赋值
- bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx);
- //在第n个节点后插入s指向的节点
- bool InsDListNode(ptrLinkList L, ptrDListNode s, int n);
- //删除第n个节点 用q返回
- bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n);
- //打印链表
- void links_print(ptrLinkList L, DListDataPrintFunc);
- //遍历链表 根据回调函数 用ctx返回所求结果
- bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx);
- #endif//
#ifndef LINKS_H_
#define LINKS_H_
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#define LEN_LIST sizeof(DListNode)
typedef bool (*DListDataPrintFunc)(void* data); //打印链表的回调函数接口
typedef bool (*DListVistFunc)(void* data, void* ctx); //遍利链表的回掉函数接口
typedef bool (*DListDataAssign)(void* data, void* ctx);
typedef struct _DListNode{
struct _DListNode* prev;
struct _DListNode* next;
void * data;
//int data;
}DListNode,*ptrDListNode;
typedef struct {
ptrDListNode head,tail;
int len;
}LinkList,*ptrLinkList;
//开辟一个节点 返回指向该节点的指针
ptrDListNode CreateNode();
//释放一个节点内存 返回空指针值
ptrDListNode DestroyDListNode(ptrDListNode e);
//初始化一个链表头节点
ptrLinkList InitList();
//销毁一个链表头节点 以及链表内所有元素 返回NULL
ptrLinkList DestroyLinkList(ptrLinkList L);
//为链表的节点赋值
bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx);
//在第n个节点后插入s指向的节点
bool InsDListNode(ptrLinkList L, ptrDListNode s, int n);
//删除第n个节点 用q返回
bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n);
//打印链表
void links_print(ptrLinkList L, DListDataPrintFunc);
//遍历链表 根据回调函数 用ctx返回所求结果
bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx);
#endif//
links.c
- #include "links.h"
- //给节点data赋值
- bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx)
- {
- assign(data,ctx);
- }
- //开辟一个结点
- ptrDListNode CreateNode(int size_data)
- {
- ptrDListNode p = (ptrDListNode) malloc(LEN_LIST);
- p->prev = NULL;
- p->next = NULL;
- p->data = (void*) malloc(size_data);
- return p;
- }
- //初始化头节点
- ptrLinkList InitList()
- {
- ptrLinkList L = (ptrLinkList) malloc(sizeof(LinkList));
- L->head = NULL;
- L->tail = NULL;
- L->len = 0;
- return L;
- }
- //销毁一个节点
- ptrDListNode DestroyDListNode(ptrDListNode e)
- {
- free(e->data);
- free(e);
- e = NULL;
- return NULL;
- }
- //销毁整个链表
- ptrLinkList DestroyLinkList(ptrLinkList L)
- {
- ptrDListNode p = L->head;
- int n = L->len;
- while(n--)
- {
- p = p->next;
- DestroyDListNode(L->head);
- L->head = p;
- }
- free(L);
- return NULL;
- }
- //在第一个节点前插入
- static void InsFirst(ptrLinkList L, ptrDListNode s)
- {
- ptrDListNode p = L->head;
- L->head = s;
- s->prev = NULL;
- if(L->len == 0)
- {
- L->tail = s;
- s->next = NULL;
- }
- else{
- s->next = p;
- p->prev = s;
- }
- L->len++;
- }
- //在第n个节点后插入
- bool InsDListNode(ptrLinkList L, ptrDListNode s, int n)
- {
- if(n > L->len || n < 0 ) return false;
- if(!n){
- InsFirst(L,s);
- return true;
- }
- ptrDListNode p = L->head;
- if(n == L->len) L->tail = s;
- while(--n)
- {
- p = p->next;
- }
- s->next = p->next;
- p->next = s;
- s->prev = p;
- if(L->tail != s)
- s->next->prev = s;
- else s->next = NULL;
- L->len ++;
- return true;
- }
- //删除第一个节点q返回
- static bool DelFirst(ptrLinkList L, ptrDListNode* q)
- {
- if(L->len == 0) return false;
- *q = L->head;
- if(L->len == 1){
- L->head = NULL;
- L->tail = NULL;
- }
- else
- {
- L->head = L->head->next;
- L->head->prev = NULL;
- }
- (*q)->next = NULL;
- L->len--;
- return true;
- }
- //删除第n个节点 q你返回
- bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n)
- {
- if(n > L->len || n < 0) return false;
- if(!n)
- {
- DelFirst(L,q);
- return true;
- }
- ptrDListNode p = L->head;
- while(--n)
- {
- p = p->next;
- }
- if(p == L->tail){
- L->tail = p->prev;
- }
- else
- p->next->prev = p->prev;
- p->prev->next = p->next;
- *q = p;
- (*q)->next = NULL;
- (*q)->prev = NULL;
- L->len--;
- return true;
- }
- //遍历访问
- bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx)
- {
- ptrDListNode p = L->head;
- int n = L->len;
- long long* ctx_temp = ctx;
- *ctx_temp = 0;
- while(n--)
- {
- visit(p->data, ctx);
- p = p->next;
- }
- return true;
- }
- //遍历打印
- void links_print(ptrLinkList L, DListDataPrintFunc print)
- {
- ptrDListNode p = L->head;
- int n = L->len;
- while(n--)
- {
- print(p->data);
- putchar('\n');
- p = p->next;
- }
- }
#include "links.h"
//给节点data赋值
bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx)
{
assign(data,ctx);
}
//开辟一个结点
ptrDListNode CreateNode(int size_data)
{
ptrDListNode p = (ptrDListNode) malloc(LEN_LIST);
p->prev = NULL;
p->next = NULL;
p->data = (void*) malloc(size_data);
return p;
}
//初始化头节点
ptrLinkList InitList()
{
ptrLinkList L = (ptrLinkList) malloc(sizeof(LinkList));
L->head = NULL;
L->tail = NULL;
L->len = 0;
return L;
}
//销毁一个节点
ptrDListNode DestroyDListNode(ptrDListNode e)
{
free(e->data);
free(e);
e = NULL;
return NULL;
}
//销毁整个链表
ptrLinkList DestroyLinkList(ptrLinkList L)
{
ptrDListNode p = L->head;
int n = L->len;
while(n--)
{
p = p->next;
DestroyDListNode(L->head);
L->head = p;
}
free(L);
return NULL;
}
//在第一个节点前插入
static void InsFirst(ptrLinkList L, ptrDListNode s)
{
ptrDListNode p = L->head;
L->head = s;
s->prev = NULL;
if(L->len == 0)
{
L->tail = s;
s->next = NULL;
}
else{
s->next = p;
p->prev = s;
}
L->len++;
}
//在第n个节点后插入
bool InsDListNode(ptrLinkList L, ptrDListNode s, int n)
{
if(n > L->len || n < 0 ) return false;
if(!n){
InsFirst(L,s);
return true;
}
ptrDListNode p = L->head;
if(n == L->len) L->tail = s;
while(--n)
{
p = p->next;
}
s->next = p->next;
p->next = s;
s->prev = p;
if(L->tail != s)
s->next->prev = s;
else s->next = NULL;
L->len ++;
return true;
}
//删除第一个节点q返回
static bool DelFirst(ptrLinkList L, ptrDListNode* q)
{
if(L->len == 0) return false;
*q = L->head;
if(L->len == 1){
L->head = NULL;
L->tail = NULL;
}
else
{
L->head = L->head->next;
L->head->prev = NULL;
}
(*q)->next = NULL;
L->len--;
return true;
}
//删除第n个节点 q你返回
bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n)
{
if(n > L->len || n < 0) return false;
if(!n)
{
DelFirst(L,q);
return true;
}
ptrDListNode p = L->head;
while(--n)
{
p = p->next;
}
if(p == L->tail){
L->tail = p->prev;
}
else
p->next->prev = p->prev;
p->prev->next = p->next;
*q = p;
(*q)->next = NULL;
(*q)->prev = NULL;
L->len--;
return true;
}
//遍历访问
bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx)
{
ptrDListNode p = L->head;
int n = L->len;
long long* ctx_temp = ctx;
*ctx_temp = 0;
while(n--)
{
visit(p->data, ctx);
p = p->next;
}
return true;
}
//遍历打印
void links_print(ptrLinkList L, DListDataPrintFunc print)
{
ptrDListNode p = L->head;
int n = L->len;
while(n--)
{
print(p->data);
putchar('\n');
p = p->next;
}
}
test.c
- #include <stdio.h>
- #include "links.h"
- #define DATA_SIZE sizeof(Node)
- typedef struct Node{
- int a;
- int b;
- }Node,*ptrNode;
- static bool Data_Assign(void* data, ptrNode ctx)
- {
- ptrNode temp = data;
- temp->a = ctx->a;
- temp->b = ctx->b;
- return true;
- }
- static bool print_int(void* data)
- {
- ptrNode temp = data;
- printf("%d %d",temp->a, temp->b);
- return true;
- }
- static bool get_sum(void* data, void* ctx)
- {
- ptrNode temp = data;
- long long* result = ctx;
- *result += temp->b;
- return true;
- }
- static bool find_max(void* data, void* ctx)
- {
- ptrNode temp = data;
- int* pimax = ctx;
- if(*pimax < temp->a) *pimax = temp->a;
- return true;
- }
- int main()
- {
- int i;
- ptrLinkList p = InitList();
- ptrDListNode s = CreateNode(DATA_SIZE);
- ptrDListNode s1 = CreateNode(DATA_SIZE);
- ptrDListNode s2 = CreateNode(DATA_SIZE);
- ptrDListNode s3 = CreateNode(DATA_SIZE);
- ptrDListNode s4;
- long long sum;
- int imax;
- Node ss[5];
- for(i = 1; i<5; i++)
- {
- ss[i].a = i;
- ss[i].b = i*10 + i;
- }
- DListNodeGetData(s->data, Data_Assign, &ss[1]);
- DListNodeGetData(s1->data, Data_Assign, &ss[2]);
- DListNodeGetData(s2->data, Data_Assign, &ss[3]);
- DListNodeGetData(s3->data, Data_Assign, &ss[4]);
- InsDListNode(p,s,0);
- InsDListNode(p,s1,0);
- InsDListNode(p,s2,0);
- InsDListNode(p,s3,3);
- links_print(p,print_int);
- Dlist_Foreach(p, get_sum, &sum);
- Dlist_Foreach(p, find_max, &imax);
- printf("%lld %d\n",sum,imax);
- DestroyLinkList(p);
- return 0;
- }
#include <stdio.h>
#include "links.h"
#define DATA_SIZE sizeof(Node)
typedef struct Node{
int a;
int b;
}Node,*ptrNode;
static bool Data_Assign(void* data, ptrNode ctx)
{
ptrNode temp = data;
temp->a = ctx->a;
temp->b = ctx->b;
return true;
}
static bool print_int(void* data)
{
ptrNode temp = data;
printf("%d %d",temp->a, temp->b);
return true;
}
static bool get_sum(void* data, void* ctx)
{
ptrNode temp = data;
long long* result = ctx;
*result += temp->b;
return true;
}
static bool find_max(void* data, void* ctx)
{
ptrNode temp = data;
int* pimax = ctx;
if(*pimax < temp->a) *pimax = temp->a;
return true;
}
int main()
{
int i;
ptrLinkList p = InitList();
ptrDListNode s = CreateNode(DATA_SIZE);
ptrDListNode s1 = CreateNode(DATA_SIZE);
ptrDListNode s2 = CreateNode(DATA_SIZE);
ptrDListNode s3 = CreateNode(DATA_SIZE);
ptrDListNode s4;
long long sum;
int imax;
Node ss[5];
for(i = 1; i<5; i++)
{
ss[i].a = i;
ss[i].b = i*10 + i;
}
DListNodeGetData(s->data, Data_Assign, &ss[1]);
DListNodeGetData(s1->data, Data_Assign, &ss[2]);
DListNodeGetData(s2->data, Data_Assign, &ss[3]);
DListNodeGetData(s3->data, Data_Assign, &ss[4]);
InsDListNode(p,s,0);
InsDListNode(p,s1,0);
InsDListNode(p,s2,0);
InsDListNode(p,s3,3);
links_print(p,print_int);
Dlist_Foreach(p, get_sum, &sum);
Dlist_Foreach(p, find_max, &imax);
printf("%lld %d\n",sum,imax);
DestroyLinkList(p);
return 0;
}
因为第一次写,首先写了一个固定int型数据的链表,实现了基本的插入删除操作。为了通用性开始使用void*来存数据段,因为指针一块儿仍旧是眼高手低基础不牢,先假设是非结构体数据进行测试,编写了几个常规的回调函数,实现遍历打印,遍历求和,遍历求最大值。
毕竟绝大多数的链表数据段都是存储的结构体,真正存储结构体的时候又涉及到void型指针进行内存分配的问题,这里依旧需要用回调函数来完成,毕竟内部函数不知道到底是怎样的一个结构体。
整体代码测试通过,由于在linux下编写的,gdb调试用的不熟练,效率太低,而且使用makefile之后我都不会用gdb调试了,list都不出代码了,脑袋完全大了。这次也是人生第一次编写makefile文件。贴出来吧,以后回来改,估计是makefile写的有问题才整的gdb调试的时候只能run不能list....
makefile
- test:test.o links.o
- gcc test.o links.o -o test
- test.o:test.c links.h
- gcc -c -g test.c
- links.o:links.c links.h
- gcc -c -g links.c
- #this is a makefile
test:test.o links.o
gcc test.o links.o -o test
test.o:test.c links.h
gcc -c -g test.c
links.o:links.c links.h
gcc -c -g links.c
#this is a makefile
- 上一篇各大OJ网址
- 下一篇无options选项chmod命令简单实现
-
顶
- 0
-
踩
- 0