近期在阅读一个开源的C++代码。里面用到了大量的STL里面的东西。或许是自己一直用C而非常少用C++来实现算法的原因。STL里面大量的模板令人心烦。一直对STL的效率表示怀疑,但在网上搜到这样一个帖子,说C的标准库里面高速排序比STL的标准排序要慢!于是,便认真的看了下二者的源代码,发现C++里面的std::sort综合运用了部分高速排序和堆排序算法,而C标准库里面用的是通用数据结构的高速排序,C标准库里面的qsort之所以比std::sort慢。是由于C语言中为了适配全部的数据结构使用了空指针。以下以更为简单的插入排序为例说明这个问题。

插入排序的算法实现代码:

void insert_sort(int a[], int n)
{
int i, j;
int t;
for (i = 1; i < n; i++) {
t = a[i];
j = i;
while ((j > 0) && (a[j - 1] > t)) {
a[j] = a[j - 1];
j--;
}
a[j] = t;
}
}

上述插入排序的实现仅仅能针对整数类型进行排序,假设数据类型是浮点型。则要自己又一次把代码拷贝一份。而且更改函数名以及数据类型。

假设是双精度的,又或者是对自己定义的结构体数组进行排序呢? 显然,这不是一种非常好的解决方式。 而用空指针能够解决问题。

通用数据类型的插入排序实现代码:

void general_insert_sort(void* arr, int num_element, int element_bytes, int (*cmp_fun)(void* p1, void* p2))
{
int i, j;
int t[1024];
if (element_bytes > 4096){
return;
}
#define ELE(arr, i) (void*)(((unsigned)arr) + (i) * element_bytes)
for (i = 1; i < num_element; i++) {
memcpy(t, ELE(arr, i), element_bytes);
j = i;
while ((j > 0) && (cmp_fun(ELE(arr, j - 1), (void*)t))) {
memcpy(ELE(arr, j), ELE(arr, j - 1), element_bytes);
j--;
}
memcpy(ELE(arr, j), (void*)t, element_bytes);
}
}

上述通用插入排序的实现有一个限制。就是待排序数组里面每个元素的大小不能超过4k,当然对于简单的系统提前定义好的数据类型,数组元素的大小最大为double,仅仅有8个字节,这是远远的足够用的。假设你自己定义的结构体的大小太大,比如大于这里设置的4K,则没有必要用此方法排序,由于此时数据移动会占用大部分时间,此时应该考虑用索引排序的方法。

上面的方法尽管攻克了随意数据类型的问题,可是其效率并不怎么高。相对于上述第一段代码而言,简单的赋值语句必须得调用一个函数来拷贝数据。简单的比較语句,则须要调用外部传入一个函数指针得到比較结果。

这是效率低下的根本原因。

而C++模板參数的出现,仅仅须要写一份代码,编译器依据你调用时候的数据类型自己主动生成新的代码。其有用宏也能够完毕通用的功能。这里给出C语言宏的代码。C++模板的代码也非常easy。

#define FIV_IMPLEMENT_INSETT_SORT(function_name, T, LT_CMP)\
void function_name(T* arr, int low, int high)\
{\
int i, j;\
T t;\
for (i = low + 1; i < high; i++) {\
t = arr[i];\
j = i;\
while ((j > low) && (LT_CMP(t, arr[j - 1]))) {\
arr[j] = arr[j - 1];\
j--;\
}\
arr[j] = t;\
}\
}

上面的宏定义能够看做是一种模板定义,能够用于随意数据类型。

假设你要对整数进行排序。非常easy,用以下的两个宏。一个宏定义比較运算。一个宏为函数定义:

#define  CMP(a, b)    ((a) < (b))
FIV_IMPLEMENT_INSETT_SORT(insert_sort_int, int, CMP)

这样就有一个用于整数排序的函数insert_sort_int可用,假设是你自己定义的结构体类型,则相同仅仅须要写这两个宏就能够了。

结尾:

用C++模板产生的代码大小是不使用模板的非常多倍,而用C语言的空指针能够支持随意数据类型,代码大小非常小,而用C语言的宏定义产生模板函数的代码大小理论上和使用STL的大小是一样的。

经过本人測试。随便一个特定数据结构的高速排序递归实现,都比c++ stl里面的std::sort要快

C语言实现通用数据结构的高效设计的更多相关文章

  1. GDSL 1.7 发布,C语言通用数据结构库

    GDSL 1.7 修复了 interval-heap 模块的一个小 bug. GDSL (通用数据结构库) 包含一组程序用于操作各种数据结构.这是一个可移植的库,完全由 ANSI C 编写.为 C 开 ...

  2. 1. C语言中的数据结构.md

    C语言内建数据结构类型 整型 整型数据是最基本的数据类型,不过从整形出发衍生出好几种integer-like数据结构,譬如字符型,短整型,整型,长整型.他们都是最基本的方式来组织的数据结构,一般是几位 ...

  3. ASP.NET通用权限组件思路设计

    开篇 做任何系统都离不开和绕不过权限的控制,尤其是B/S系统工作原理的特殊性使得权限控制起来更为繁琐,所以就在想是否可以利用IIS的工作原理,在IIS处理客户端请求的某个入口或出口通过判断URL来达到 ...

  4. Abp通用配置模块的设计

    引言 约定优于配置,配置趋于灵活 约定优于配置(convention over configuration),也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处, ...

  5. Atitit. 脚本语言的断点单步调试的设计与实现 attialx 总结 php 参照java

    Atitit. 脚本语言的断点单步调试的设计与实现 attialx 总结 php 参照java 1. 断点的实现:手动断点 die和exit是等价的 1 2. 变量表的实现 1 3. print_r( ...

  6. JavaScript 与 Java 是两种完全不同的语言,无论在概念还是设计上。

    JavaScript 与 Java 是两种完全不同的语言,无论在概念还是设计上. Java(由 Sun 发明)是更复杂的编程语言. ECMA-262 是 JavaScript 标准的官方名称. Jav ...

  7. C语言实现通用链表初步(一)

    注意:本文讨论的是无头单向非循环链表. 假设不采用Linux内核链表的思路,怎样用C语言实现通用链表呢? 一种常用的做法是: typedef int element_t; struct node_in ...

  8. Atitit.跨语言系统服务管理器api兼容设计

    Atitit.跨语言系统服务管理器api兼容设计 1. Common api,兼容sc ,service control??1 1.1. 服务创建,use sc1 1.2. 服务delete ,use ...

  9. Cocos2d-x 脚本语言Lua基本数据结构-表(table)

    Cocos2d-x 脚本语言Lua基本数据结构-表(table) table是Lua中唯一的数据结构.其它语言所提供的数据结构,如:arrays.records.lists.queues.sets等. ...

随机推荐

  1. 蓝桥杯java高职组

    标题1: 猜年龄     美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学.他曾在1935~1936年应邀来中 国清华大学讲学.     一次,他参加某个重要会议,年轻的脸孔引人注目.于是 ...

  2. The type MultipartEntity is deprecated

    在HttpCient4.3之前上传文件主要使用MultipartEntity这个类,但如今这个类已经不在推荐使用了(过时了).随之替代它的类是MultipartEntityBuilder.关于Mult ...

  3. android压缩解压zip文件

    网上各种方法的收集: 1.上次写了个解压缩功能,但有局限性,比如压缩文件xx.zip 里包括子目录的情况下,执行上次解压缩的功能就不能实现我们想要的效果,于是在网上参考了一下java的解压缩功能.对上 ...

  4. 非确定有限状态自动机的构建(一)——NFA的定义和实现

    保留版权,转载需注明出处(http://blog.csdn.net/panjunbiao). 非确定有限状态自动机(Nondeterministic Finite Automata,NFA)由以下元素 ...

  5. [转]java开发环境搭建

    分成两个部分: 1.下载安装jdk,并配置环境变量 链接:http://www.runoob.com/java/java-environment-setup.html 2.安装Eclipse 链接:h ...

  6. Java 23种设计模式详尽分析与实例解析之三--行为型模式

    Java设计模式 行为型模式 职责链模式 模式动机:职责链可以是一条直线.一个环或者一个树形结构.链上的每一个对象都是请求处理者,职责链模式可以将请求的处理组织成一条链,并使请求链传递,由链上的处理者 ...

  7. Magento给产品添加“new”或者折扣数量标签 magento new label. discount label

    文章最底部有效果图. 给新产品添加“new”的标签.给折扣产品,显示出折扣的数量. 这个可以自己写一段代码加在到模板文件夹下面的catalog/product/list.phtml中. 以下是代码 & ...

  8. C++学习笔记14,private/protected/public继承,私有继承,保护继承,公有继承(五)(总结)

    各种继承方式: 特征 公有继承 保护继承 私有继承 公有成员变为 派生类的公有成员 派生类的保护成员 派生类的私有成员 保护成员变为 派生类的保护成员 派生类的保护成员 派生类的私有成员 私有成员变为 ...

  9. 【图论】2-sat总结

    2-sat总结 2-sat问题,一般表现的形式为.每一个点有两种方式a,b,要么选a,要么选b.而且点点之间有一些约束关系.比如:u和v至少一个选a.那么这就是一个表达式.把a当成真,b当成假,那就是 ...

  10. Eclipse设置Android Logcat输出字体大小

    Window -> Preferences -> Android -> Logcat -> Display Font:点击"Change"button 如图 ...