一个通用链表的简单实现

一个通用链表的简单实现

分类: C program Linux 1657人阅读 评论(0) 收藏 举报

最近在CSDN上看到了absurd大神的几篇关于系统程序员成长计划的的博文

里面提到了关于通用链表实现的思想,虽然数据结构学的还行,但是真的没写过通用的链表,对封装的认识比较浅显!

于是乎决定实现一下,真正开始写才发现,对我这么个眼高手低的菜鸟来说挺有难度的。写篇博文记录下。


整体实现的主题思想还是absurd大神博文中的两个重要思想:

1, 链表数据段存指针void*

2 采用回调函数来使的链表的基本函数更有通用性

贴代码:

links.h

  1. #ifndef LINKS_H_  
  2. #define LINKS_H_  
  3.   
  4. #include <malloc.h>  
  5. #include <stdbool.h>  
  6. #include <stdio.h>  
  7.   
  8. #define LEN_LIST sizeof(DListNode)  
  9.   
  10. typedef bool (*DListDataPrintFunc)(void* data);   //打印链表的回调函数接口  
  11.   
  12. typedef bool (*DListVistFunc)(void* data, void* ctx); //遍利链表的回掉函数接口  
  13. typedef bool (*DListDataAssign)(void* data, void* ctx);  
  14.   
  15. typedef struct _DListNode{  
  16.     struct _DListNode* prev;  
  17.     struct _DListNode* next;  
  18.     void * data;  
  19.     //int data;  
  20. }DListNode,*ptrDListNode;  
  21.   
  22. typedef struct {  
  23.     ptrDListNode head,tail;  
  24.     int len;  
  25. }LinkList,*ptrLinkList;  
  26.   
  27.   
  28. //开辟一个节点 返回指向该节点的指针  
  29. ptrDListNode CreateNode();  
  30.   
  31. //释放一个节点内存 返回空指针值  
  32. ptrDListNode DestroyDListNode(ptrDListNode e);  
  33.   
  34. //初始化一个链表头节点  
  35. ptrLinkList InitList();  
  36.   
  37. //销毁一个链表头节点 以及链表内所有元素 返回NULL  
  38. ptrLinkList DestroyLinkList(ptrLinkList L);  
  39.   
  40. //为链表的节点赋值   
  41. bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx);  
  42.   
  43. //在第n个节点后插入s指向的节点  
  44. bool InsDListNode(ptrLinkList L, ptrDListNode s, int n);  
  45.   
  46. //删除第n个节点 用q返回  
  47. bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n);  
  48.   
  49. //打印链表  
  50. void links_print(ptrLinkList L, DListDataPrintFunc);  
  51.   
  52. //遍历链表 根据回调函数 用ctx返回所求结果  
  53. bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx);  
  54.   
  55. #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

  1. #include "links.h"  
  2.   
  3.   
  4.   
  5.   
  6. //给节点data赋值  
  7. bool DListNodeGetData(void* data, DListDataAssign assign, void* ctx)  
  8. {  
  9.     assign(data,ctx);  
  10. }  
  11.   
  12.   
  13. //开辟一个结点  
  14. ptrDListNode CreateNode(int size_data)  
  15. {  
  16.     ptrDListNode p = (ptrDListNode) malloc(LEN_LIST);  
  17.     p->prev = NULL;  
  18.     p->next = NULL;  
  19.     p->data = (void*) malloc(size_data);  
  20.     return p;     
  21. }  
  22.   
  23.   
  24. //初始化头节点  
  25. ptrLinkList InitList()  
  26. {  
  27.     ptrLinkList L = (ptrLinkList) malloc(sizeof(LinkList));  
  28.     L->head = NULL;  
  29.     L->tail = NULL;  
  30.     L->len = 0;  
  31.     return L;  
  32. }  
  33.   
  34. //销毁一个节点  
  35.   
  36. ptrDListNode DestroyDListNode(ptrDListNode e)  
  37. {  
  38.     free(e->data);  
  39.     free(e);  
  40.     e = NULL;  
  41.     return NULL;  
  42. }  
  43.   
  44. //销毁整个链表  
  45.   
  46. ptrLinkList DestroyLinkList(ptrLinkList L)  
  47. {  
  48.     ptrDListNode p = L->head;  
  49.     int n = L->len;  
  50.     while(n--)  
  51.     {  
  52.         p = p->next;  
  53.         DestroyDListNode(L->head);  
  54.         L->head = p;  
  55.     }  
  56.     free(L);  
  57.     return NULL;  
  58. }  
  59.   
  60. //在第一个节点前插入  
  61. static void InsFirst(ptrLinkList L, ptrDListNode s)  
  62. {  
  63.     ptrDListNode p = L->head;  
  64.     L->head = s;  
  65.     s->prev = NULL;  
  66.     if(L->len == 0)  
  67.     {  
  68.         L->tail = s;  
  69.         s->next = NULL;  
  70.     }  
  71.     else{  
  72.         s->next = p;  
  73.         p->prev = s;  
  74.     }  
  75.     L->len++;  
  76. }  
  77.   
  78. //在第n个节点后插入  
  79. bool InsDListNode(ptrLinkList L, ptrDListNode s, int n)  
  80. {  
  81.     if(n > L->len || n < 0 ) return false;  
  82.     if(!n){  
  83.         InsFirst(L,s);  
  84.         return true;  
  85.     }  
  86.     ptrDListNode p = L->head;  
  87.     if(n == L->len) L->tail = s;   
  88.     while(--n)  
  89.     {  
  90.         p = p->next;  
  91.     }  
  92.     s->next = p->next;  
  93.     p->next = s;  
  94.     s->prev = p;  
  95.     if(L->tail != s)  
  96.         s->next->prev = s;  
  97.     else    s->next = NULL;  
  98.     L->len ++;  
  99.     return true;  
  100. }  
  101.   
  102. //删除第一个节点q返回  
  103. static bool DelFirst(ptrLinkList L, ptrDListNode* q)  
  104. {  
  105.     if(L->len == 0) return false;  
  106.     *q = L->head;  
  107.     if(L->len == 1){  
  108.       L->head = NULL;  
  109.       L->tail = NULL;  
  110.     }   
  111.     else  
  112.     {  
  113.         L->head = L->head->next;  
  114.         L->head->prev = NULL;  
  115.     }  
  116.     (*q)->next = NULL;  
  117.     L->len--;  
  118.     return true;  
  119. }  
  120.   
  121. //删除第n个节点 q你返回  
  122. bool DelDListNode(ptrLinkList L, ptrDListNode* q, int n)  
  123. {  
  124.     if(n > L->len || n < 0) return false;  
  125.     if(!n)  
  126.     {  
  127.         DelFirst(L,q);  
  128.         return true;  
  129.     }  
  130.     ptrDListNode p = L->head;  
  131.     while(--n)  
  132.     {  
  133.         p = p->next;  
  134.     }  
  135.     if(p == L->tail){  
  136.         L->tail = p->prev;  
  137.   
  138.     }  
  139.     else  
  140.         p->next->prev = p->prev;  
  141.     p->prev->next = p->next;  
  142.     *q = p;  
  143.     (*q)->next = NULL;  
  144.     (*q)->prev = NULL;  
  145.     L->len--;  
  146.     return true;  
  147. }  
  148.   
  149.   
  150. //遍历访问  
  151. bool Dlist_Foreach(ptrLinkList L, DListVistFunc visit, void* ctx)  
  152. {  
  153.     ptrDListNode p = L->head;  
  154.     int n = L->len;  
  155.     long long* ctx_temp = ctx;  
  156.     *ctx_temp = 0;  
  157.     while(n--)  
  158.     {  
  159.         visit(p->data, ctx);  
  160.         p = p->next;  
  161.     }  
  162.     return true;  
  163. }  
  164.   
  165. //遍历打印  
  166. void links_print(ptrLinkList L, DListDataPrintFunc print)  
  167. {  
  168.     ptrDListNode p = L->head;  
  169.     int n = L->len;  
  170.     while(n--)  
  171.     {  
  172.         print(p->data);  
  173.         putchar('\n');  
  174.         p = p->next;  
  175.     }  
  176. }  
#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

  1. #include <stdio.h>  
  2. #include "links.h"  
  3. #define DATA_SIZE sizeof(Node)  
  4.   
  5.   
  6. typedef struct Node{  
  7.     int a;  
  8.     int b;  
  9. }Node,*ptrNode;  
  10.   
  11.   
  12. static bool Data_Assign(void* data, ptrNode ctx)  
  13. {  
  14.     ptrNode temp  = data;  
  15.     temp->a = ctx->a;  
  16.     temp->b = ctx->b;  
  17.     return true;  
  18. }  
  19.   
  20. static bool print_int(void* data)  
  21. {  
  22.     ptrNode temp = data;  
  23.     printf("%d %d",temp->a, temp->b);  
  24.     return true;  
  25. }  
  26.   
  27.   
  28. static bool get_sum(void* data, void* ctx)  
  29. {  
  30.     ptrNode temp = data;  
  31.     long long* result = ctx;  
  32.     *result += temp->b;  
  33.     return true;  
  34. }  
  35.   
  36. static bool find_max(void* data, void* ctx)  
  37. {  
  38.     ptrNode temp = data;  
  39.     int* pimax = ctx;  
  40.     if(*pimax < temp->a) *pimax = temp->a;  
  41.     return true;  
  42. }  
  43.   
  44.   
  45. int main()  
  46. {  
  47.     int i;  
  48.     ptrLinkList p = InitList();  
  49.     ptrDListNode s = CreateNode(DATA_SIZE);  
  50.     ptrDListNode s1 = CreateNode(DATA_SIZE);  
  51.     ptrDListNode s2 = CreateNode(DATA_SIZE);  
  52.     ptrDListNode s3 = CreateNode(DATA_SIZE);  
  53.     ptrDListNode s4;  
  54.     long long sum;  
  55.     int imax;  
  56.     Node ss[5];  
  57.     for(i = 1; i<5; i++)  
  58.     {  
  59.         ss[i].a = i;  
  60.         ss[i].b = i*10 + i;  
  61.     }  
  62.     DListNodeGetData(s->data, Data_Assign, &ss[1]);  
  63.     DListNodeGetData(s1->data, Data_Assign, &ss[2]);  
  64.     DListNodeGetData(s2->data, Data_Assign, &ss[3]);  
  65.     DListNodeGetData(s3->data, Data_Assign, &ss[4]);  
  66.     InsDListNode(p,s,0);  
  67.     InsDListNode(p,s1,0);  
  68.     InsDListNode(p,s2,0);  
  69.     InsDListNode(p,s3,3);  
  70.     links_print(p,print_int);  
  71.     Dlist_Foreach(p, get_sum, &sum);  
  72.     Dlist_Foreach(p, find_max, &imax);  
  73.     printf("%lld %d\n",sum,imax);  
  74.     DestroyLinkList(p);  
  75.     return 0;  
  76. }  
#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

  1. test:test.o links.o  
  2.     gcc test.o links.o -o test  
  3. test.o:test.c links.h  
  4.     gcc -c -g test.c   
  5. links.o:links.c links.h  
  6.     gcc -c -g links.c   
  7. #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


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值