扩展开发和嵌入式在数组和哈希表上工作

上传人:第*** 文档编号:122297981 上传时间:2020-03-03 格式:DOCX 页数:31 大小:56.59KB
返回 下载 相关 举报
扩展开发和嵌入式在数组和哈希表上工作_第1页
第1页 / 共31页
扩展开发和嵌入式在数组和哈希表上工作_第2页
第2页 / 共31页
扩展开发和嵌入式在数组和哈希表上工作_第3页
第3页 / 共31页
扩展开发和嵌入式在数组和哈希表上工作_第4页
第4页 / 共31页
扩展开发和嵌入式在数组和哈希表上工作_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《扩展开发和嵌入式在数组和哈希表上工作》由会员分享,可在线阅读,更多相关《扩展开发和嵌入式在数组和哈希表上工作(31页珍藏版)》请在金锄头文库上搜索。

1、在数组和哈希表上工作在C语言中, 有两种不同的基础方法用来在一个结构体中存储任意数量的独立数据元素. 两种方法都有赞成者和反对者.向量 Vs. 链表应用的编写通常基于特定类型数据的特性的选择, 需要存储多少数据, 以及需要多快速度的检索. 为了能够有对等的认知, 我们先来看看简单的看看这些存储机制.向量向量是一块连续的内存空间, 它们包含的数据有规律的间隔. 向量最常见的例子就是字符串变量(char *或char ), 它包含了一个接着一个的字符(字节)序列.char foo4 = bar;这里, foo0包含了字符b; 紧接着, 你将在foo1中找到字符a, 最后在foo3中是一个空字符0.

2、将指向其他结构的指针存储到向量中的用法几乎是无所不在的, 比如在上一章, 使用zend_get_parameters_array_ex()函数时, 就使用了一个zval的向量. 那里, 我们看到var_dump()定义了一个zval *的函数变量, 接着为它分配空间用来存储zval *指针(最终的数据来自zend_get_parameters_ex()调用)zval *args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);和访问字符串中的数组一样, var_dump()实现中使用argsi依次传递每个zval *元素到内部函数php_va

3、r_dump().向量最大的优点在于运行时单个元素的访问速度. argsi这样的变量引用, 可以很快的计算出它的数据地址(args + i * sizeof(args0). 这个索引结构的空间分配和释放是在单次, 高效的调用中完成的.链表另外一种常见的存储数据的方式是链表. 对于链表而言, 每个数据元素都是一个至少有两个属性的结构体: 一个指向链表中的下一个节点, 一个则是实际的数据. 考虑下面假设的数据结构:typedef struct _namelist namelist;struct struct namelist *next; char *name; _namelist;使用这个数据结

4、构的引用需要定义一个变量:static namelist *people;链表中的第一个名字可以通过检查people变量的name属性得到: people-name; 第二个名字则访问next属性: people-next-name, 依此类推: people-next-next-name等等, 直到next为NULL表示链表中已经没有其他名字了. 更常见的用法是使用循环迭代链表:void name_show(namelist *p) while (p) printf(Name: %sn, p-name); p = p-next; 这种链表非常适合于FIFO的链式结构, 新的数据被追加到链表的

5、末尾, 从另外一端线性的消耗数据:static namelist *people = NULL, *last_person = NULL;void name_add(namelist *person) person-next = NULL; if (!last_person) /* 链表中没有数据 */ people = last_person = person; return; /* 向链表末尾增加新的数据 */ last_person-next = person; /* 更新链表尾指针 */ last_person = person;namelist *name_pop(void) nam

6、elist *first_person = people; if (people) people = people-next; return first_person;新的namelist结构可以从这个链表中多次插入或弹出, 而不用调整结构的大小或在某些位置间块拷贝元素.前面你看到的链表只是一个单链表, 虽然它有一些有趣的特性, 但它有致命的缺点. 给出链表中一项的指针, 将它从链中剪切出来并确保前面的元素正确的链接上下一个元素就变得比较困难.为了知道它的前一个元素, 就需要遍历整个链表直到找到一个元素的next指针指向要被删除的元素. 对于大的链表, 这可能需要可观的CPU时间. 一个简单的

7、相对廉价的解决方案是双链表.对于双链表而言, 每个元素增加了一个指针元素, 它指向链表中的前一个元素:typedef struct _namelist namelist;struct namelist *next, *prev; char *name; _namelist;一个元素被添加到双链表的时候, 这两个指针相应的都被更新:void name_add(namelist *person) person-next = NULL; if (!last_person) /* 链表中没有元素 */ people = last_person = person; person-prev = NULL;

8、 return; /* 在链表尾增加一个新元素 */ last_person -next = person; person-prev = last_person; /* 更新链表尾指针 */ last_person = person;迄今为止, 你还没有看到这种数据结构的任何优势, 但是现在你可以想想, 给出people链表中间的一条任意的namelist记录, 怎样删除它. 对于单链表, 你需要这样做:void name_remove(namelist *person) namelist *p; if (person = people) /* 要删除链表头指针 */ people = per

9、son-next; if (last_person = person) /* 要删除的节点同时还是尾指针 */ last_person = NULL; return; /* 搜索要删除节点的前一个节点 */ p = people; while (p) if (p-next = person) /* 删除 */ p-next = person-next; if (last_person = person) /* 要删除的节点是头指针 */ last_person = p; return; p = p-next; /* 链表中没有找到对应元素 */现在和双链表的代码比较一下:void name_r

10、emove(namelist *person) if (people = person) people = person-next; if (last_person = person) last_person = person-prev; if (person-prev) person-prev-next = person-next; if (person-next) person-next-prev = person-prev; 不是很长, 也没有循环, 从链表中删除一个元素只需要简单的执行条件语句中的重新赋值语句. 与此过程相逆的过程就可以同样高效的将元素插入到链表的任意点.最好的是Has

11、hTable虽然在你的应用中你完全可以使用向量或链表, 但有另外一种集合数据类型, 最终你可能会更多的使用: HashTable.HashTable是一种特殊的双链表, 它增加了前面看到的向量方式的高效查找. HashTable在Zend引擎和php内核中使用的非常多, 整个ZendAPI都子例程都主要在处理这些结构.如你在第2章变量的里里外外中所见, 所有的用户空间变量都存储在一个zval *指针的HashTable中. 后面章节中你可以看到Zend引擎使用HashTable存储用户空间函数, 类, 资源, 自动全局标记以及其他结构.回顾第2章, Zend引擎的HashTable可以原文存储

12、任意大小的任意数据片. 比如, 函数存储了完整的结构. 自动全局变量只是很少几个字节的元素, 然而其他的结构, 比如php5的类定义则只是简单的存储了指针.本章后面我们将学习构成Zend Hash API的函数调用, 你可以在你的扩展中使用这些函数.Zend Hash APIZend Hash API被分为几个基本的打雷, 除了几个特殊的, 这些函数通常都返回SUCCESS或FAILURE.创建每个HashTable都通过一个公用的构造器初始化:int zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dt

13、or_func_t pDestructor, zend_bool persistent)ht是一个指向HashTable变量的指针, 它可以定义为直接值形式, 也可以通过emalloc()/pemalloc()动态分配, 或者更常见的是使用ALLOC_HASHTABLE(ht). ALLOC_HASHTABLE()宏使用了一个特定内存池的预分配块来降低内存分配所需的时间, 相比于ht = emalloc(sizeof(HashTable);它通常是首选.nSize应该被设置为HashTable期望存储的最大元素个数. 如果向这个HashTable中尝试增加多于这个数的元素, 它将会自动增长, 不过有一点需要注意的是, 这里Zend重建整个新扩展的HashTable的索引的过程需要耗费不少的处理时间. 如果nSize不是2的幂, 它将被按照下面公式扩展为下一个2的幂:nSize = pow(2, ceil(log(nSize, 2);pHashFunction是旧版本Zend引擎的遗留参数, 它不在使用, 因此这个值应该被设置为NULL. 在早期的Zend引擎中, 这个值指向一个用以替换标准的DJBX33A(一种常见的抗碰撞哈希算法, 用来将任意字符串key转换到可重演的整型值)的可选哈希算法.pDestructor指向当从HashTable删除元素时

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 调研报告

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号