zoukankan      html  css  js  c++  java
  • C语言实现通用数据结构的高效设计

             近期在阅读一个开源的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要快




  • 相关阅读:
    docker 加速器配置目录
    php 超时设置笔记
    php socket通过smtp发送邮件(纯文本、HTML,多收件人,多抄送,多密送)
    fabric 安装
    centos7下使用yum安装pip
    【转】linux tar 压缩
    ASP.NET MVC 5 默认模板的JS和CSS 是怎么加载的?
    NHibernate with ASP.NET MVC 入门示例
    Ajax入门
    NHibernate入门
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5126167.html
Copyright © 2011-2022 走看看