C泛型__数据结构
来源:互联网 发布:澳门网络博客官方网站 编辑:程序博客网 时间:2024/06/14 18:47
这里通过用C实现一个通用类型的栈结构来加深对数据结构和C指针的一些理解 同时也为一些C通用类型库函数(如排序)的实现提供一些思路
先写一个int 版本的栈用于比较:
以上代码能够很好的通过测试 并且运行效率相当快,在C中 我们通过对内存位模式的操作来屏蔽了所有类型及类型长度带来的差异。
typedef struct{ int* elem; int logicalLen; int allocLen;}stack;void StackNew(stack* s){ s->logicalLen = 0; s->allocLen = 4; s->elem = (int*)malloc(s->allocLen*sizeof(int));}void StackDestroy(stack* s){ free(s->elem); s->elem = NULL;}void StackPush(stack* s, int val){ if (s->logicalLen == s->allocLen) { s->allocLen *= 2; s->elem = (int*)realloc(s->elem,s->allocLen*sizeof(int)); assert(s->elem != NULL); } s->elem[s->logicalLen] = val; s->logicalLen++;}void StackPop(stack* s, int* pVal){ assert(s->logicalLen > 0); s->logicalLen--; *pVal = s->elem[s->logicalLen];}
这里通过三个变量很简便的表示了栈,当栈满时,通过扩大一倍的策略重新分配空间。为了维持操作的一致性,所有操作都无返回值。
思考一下这里为什么要传栈的地址而不直接传栈
那么接下来我们用操作内存的方式来实现通用性栈结构:
typedef struct{ int logicalLen; int allocLen; void* elems; int elemSize;}stack;void StackNew(stack* s, int size){ s->logicalLen = 0; s->allocLen = 4; s->elemSize = size; s->elems = malloc(s->allocLen*s->elemSize);}void StackDestroy(stack* s){ free (s->elems); s->elems = NULL;}void StackPush(stack* s, void* pElem){ if(s->logicalLen == s->allocLen) { s->allocLen *= 2; s->elems = realloc(s->elems, s->allocLen*s->elemSize); assert(s->elems != NULL); } void* elemlocal = (char*)s->elems+s->elemSize*s->logicalLen; memcpy(elemlocal, pElem, s->elemSize); s->logicalLen++;}void StackPop(stack* s, void*pElem){ assert(s->logicalLen != 0); void* elemlocal = (char*)s->elems+(s->logicalLen-1)*s->elemSize; memcpy(pElem, elemlocal, s->elemSize); s->logicalLen--;}
以上代码能够很好的通过测试 并且运行效率相当快,在C中 我们通过对内存位模式的操作来屏蔽了所有类型及类型长度带来的差异。
现在考虑将以上数据结构变得通用的,更灵活。假如我们要入栈出栈的元素类型是char* 这样将遇到什么问题呢?
如果我们装入的是动态分配的内存,那么我们没有理由确信栈的销毁会在栈为空之后,也就是有可能栈里还有动态分配的内存的指针,栈就被销毁了。导致内存泄漏。
解决的方案是让栈在销毁时释放动态内存空间,而栈怎么知道哪些是栈内存指针哪些是堆内存指针呢?栈不会知道,但是用户知道。因此考虑给栈多加一个用户定义的释放函数用于释放堆空间。
对上一个版本代码做少许改动:
typedef struct{ int logicalLen; int allocLen; void* elems; int elemSize; void (*freefn)(void*);}stack;void StackNew(stack* s, int size, void (*freefunc)(void*)){ s->logicalLen = 0; s->allocLen = 4; s->elemSize = size; s->elems = malloc(s->allocLen*s->elemSize); s->freefn = freefunc;}void StackDestroy(stack* s){ if(s->freefn != NULL) for(int i=0; i<s->logicalLen; i++) { s->freefn((char*)s->elems+i*s->elemSize); } free (s->elems); s->elems = NULL;}
当传入普通内置类型时,传入freefn为NULL
当传入类型是字符串时,定义freefn如下:
void freefn(void* p)
//虽然只是一个void指针 但是只要有地址 堆结构自然能知道当初分配了多少字节空间
{
free(*(char**) p);
}//考虑一下为什么不用free(char* p) 会有什么影响?
- C泛型__数据结构
- 数据结构与算法(C语言版)__交换
- 数据结构与算法(C语言版)__冒泡排序
- 数据结构与算法(C语言版)__选择排序
- 数据结构与算法(C语言版)__顺序查找
- 数据结构与算法(C语言版)__二分查找
- 数据结构与算法(C语言版)__递归
- 数据结构与算法(C语言版)__排列组合
- 数据结构与算法(C语言版)__插入排序
- 数据结构与算法(C语言版)__快速排序
- 数据结构与算法(C语言版)__归并排序
- 数据结构与算法(C语言版)__栈
- 数据结构与算法(C语言版)__队列
- 数据结构与算法(C语言版)__链表
- 数据结构与算法(C语言版)__链表2
- 数据结构与算法(C语言版)__循环链表
- 数据结构与算法(C语言版)__双向链表
- 数据结构与算法(C语言版)__链式栈
- oracle 表空间迁移,移动表空间
- 第一个Ajax程序
- Kaggle.com的数据挖掘大奖赛
- QBC查询
- struts2 获取request、session的方法
- C泛型__数据结构
- 每个初学者都应该搞懂的问题
- android短信接收过程
- 面试必备之:MFC socket编程(浅出+深度:服务端和客户端端口问题)
- java算法:递归算法
- PHP – 架構設計 Data Access Layer 篇
- Java删除文件夹和文件
- 十四. sql server max,min函数
- C系基本类型数值转换