`

《实用算法》_计算程序运行时间

 
阅读更多

对算法进行改进以求获得最佳的性能通常有两种策略:优化现有的算法,或者开发新的算法。


优化算法的标准技术:

1、使I/O减到最少,减少函数调用的次数,限制计算密集型操作(浮点数运算和除法运算);

2、确定执行得最频繁的算法元素,比如冒泡排序的比较和交换;

3、检查可能由于疏忽导致而导致特别缓慢的的实现。这往往与查找最坏情况相似。


I/O通常是发生在毫秒(ms)级的时间范围内,而CPU的活动一般发生在亚微秒级的范围内。因此对于算法而言,任何I/O的代价都非常高昂。

如果不能消除I/O本身,那么可以使用缓冲区来减小它的影响。


下面的一个算法,就是用来测试从输入文件流infile向输出文件流outfile传输时,多少大小的缓冲区buf最合适(既可以速度达到最快,也不浪费存储空间)

 

/*--- BUFSIZE.C -------------------------- Listing 1-1 --------
 * Purpose:  Demonstrate use of setvbuf
 * Usage:    bufsize infile outfile [insize [outsize]]
 * Method:   Copies infile to outfile one character at a time,
 *           reporting elapsed time. Infile is set to use a
 *           buffer of insize bytes, while outfile uses an
 *           outsize bytes buffer. Default size is 512 bytes.
 * >> Should be changed per text for UNIX systems <<
 *-----------------------------------------------------------*/

//#include <bios.h>   /* for timer function */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <windows.h>


#undef CopyFile//取消以前定义的CopyFile(下面有重写的CopyFile())
#pragma comment(lib, "kernel32.lib")//yyw

#define DEF_BUF 512//定义默认的缓冲区大小为512字节

long GetCPUTime() //获取当前时间,精度100微秒
{
	static LARGE_INTEGER li = {0};//LARGE_INTEGER是一个联合体结构
												/*
												typedef   union   _LARGE_INTEGER   {    
														struct   { 
																DWORD   LowPart;    
																LONG     HighPart;    
														}; 
														LONGLONG   QuadPart; 
											}   LARGE_INTEGER; 
												*/                                              
	                                             
	LARGE_INTEGER linow = {0};
	if (li.QuadPart == 0)
		QueryPerformanceFrequency(&li);//获取机器内部计时器的时钟频率,即每秒CPU多少次Performance Tick

	QueryPerformanceCounter(&linow);//这个函数返回高精确度性能计数器的值
	                                                       //(这个值,肯定不会是时间,应该会是系统当前计数器所显示的一个“次数”,
	                                                       //这个次数相对于下一次Counter,就可以计算出两次的时间间隔,是这样的吗?)
	return linow.QuadPart * 10000 / li.QuadPart;//得出系统当前时间,并放大10000倍,精度是100微秒
}


//根据当前的编译器环境来采用不同的库函数获取系统时钟的时间
//如果编译器是TURBO C那么就把获取系统时钟的宏get_clock_ticks(x)定义为x=biostime(0,0L)
//如果不是就定义为x=GetCPUTime()
#ifdef __TURBOC__               /* Borland   */
#define get_clock_ticks(x) x=biostime(0,0L)
#else                           /* Microsoft and Watcom */
#define get_clock_ticks(x) \
	x = GetCPUTime()//yyw
//        _bios_timeofday(_TIME_GETCLOCK, &x)//yyw
#endif


long CopyFile ( char *infilename, char *outfilename,
            size_t insize, size_t outsize )//size_t 是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。
{
    int  c;
    long starttime, donetime;
    FILE *infile, *outfile;

    /* open input file and setup its buffer */
    if (( infile = fopen ( infilename, "rb" )) == NULL)//打开文件,用infile指向输入文件流
    {
          printf ( "Can't open %s\n", infilename );
          exit ( 1 );
    }

    if ( setvbuf ( infile, NULL, _IOFBF, insize ))//setvbuf的功能就是把缓冲区与流相关。这里的缓冲区和流分别是NULL和infile
		                                                           //第2参数为NULL,是未指定缓冲区的意思?
																   //这个函数应该在打开流后,在对流做任何输入输出前,立即调用
    {
         printf ( "Couldn't set infile buffer to %u bytes.\n",
                   insize );
         exit ( 1 );
    }


    /* open output file and setup its buffer */

    if (( outfile = fopen ( outfilename, "wb" )) == NULL )//打开文件,用outfile指向输出文件流
    {
          printf ( "Can't open %s\n", outfilename );
          exit ( 1 );
    }

    if ( setvbuf ( outfile, NULL, _IOFBF, outsize ))
    {
         printf ( "Couldn't set outfile buffer to %u bytes.\n",
                   outsize );
        exit ( 1 );
    }

    /* do it */
	//开始测试
	//把输入文件转入输出文件,计算所话费的时间
	//完成后关闭输入输出文件流,返回所话费时间
    get_clock_ticks ( starttime );    /* get timer value */
    while (( c = fgetc ( infile )) != EOF )
        fputc ( c, outfile );
    get_clock_ticks ( donetime );
    fclose ( infile );
    fclose ( outfile );

    return ( donetime - starttime );
}


int main ( int argc, char *argv[] )
{
    size_t insize, outsize;
    int    i;
    long   total, average, lo, hi, elapsed;

    insize = outsize = DEF_BUF;

    if ( argc < 3 || argc > 5 )
    {
        fprintf ( stderr,
         "Usage: BUFSIZE infile outfile [insize [outsize]]\n" );
        return ( EXIT_FAILURE );
    }

    /* get buffer sizes */
    if ( argc > 3 )
         insize = (unsigned) atoi ( argv[3] );

    if ( argc > 4 )
         outsize = (unsigned) atoi ( argv[4] );

    /* now, copy the file five times */
    total = hi = 0;
    lo = LONG_MAX;
    for ( i = 1; ; i++ )
    {
        elapsed = CopyFile ( argv[1], argv[2], insize, outsize );//执行拷贝文件的操作,用elapsed存放所耗费时间
        if ( elapsed > hi )
            hi = elapsed;
        if ( elapsed < lo )
            lo = elapsed;
        total += elapsed;
		
		//累计每次所耗时间,得出总的时间
		//一旦总时间超过500ms,或者执行次数达到5次,就停止拷贝
        if ( total > 500 ||   /* Change this value depending   */
                              /*   on how long you can wait    */
                 i > 4 )      /* Do 4 passes, if time limit OK */
            break;
    }

    average = total / i;//计算平均每次拷贝的时间

    printf ( "Average of %4ld ticks (%4ld - %4ld). "
             "Insize = %5u. Outsize = %5u.\n",
             average, lo, hi, insize, outsize );

    return ( EXIT_SUCCESS );
}

 

 

该算法的思路:设置inbuf、outbuf,从infile读取存入outfile5次,记录最长时间、最短时间、平均时间。改变inbuf、outbuf,以试探得出一个比较合适的缓存buf大小。


涉及的一些类型或函数:

LARGE_INTEGER


LARGE_INTEGER是union;用于表示一64位有符号整数值.其他定义如下:    
   
typedef   union   _LARGE_INTEGER   {    
          struct   { 
                  DWORD   LowPart;    
                  LONG     HighPart;    
          }; 
          LONGLONG   QuadPart; 
}   LARGE_INTEGER; 
   
如果你有编译器直接支持64位整数可以直接使用QuadPart(64位),否则分别对LowPart(32位)和HighPart(32位)存取,HighPart的最高位为符号位。 



QueryPerformanceFrequency()

 

QueryPerformanceFrequency() - 基本介绍
类型:Win32API

原型:BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

作用:返回硬件支持的高精度计数器的频率。QueryPerformanceFrequency()提供了这个频率值,返回每秒嘀哒声的个数.

返回值:非零,硬件支持高精度计数器;零,硬件不支持,读取失败。

QueryPerformanceCounter()

QueryPerformanceCounter()这个函数返回高精确度性能计数器的值,它可以以微妙为单位计时.但是QueryPerformanceCounter()确切的精确计时的最小单位是与系统有关的,所以,必须要查询系统以得到QueryPerformanceFrequency() 返回的嘀哒声的频率.

在支持64位的编译器上,QueryPerformanceFrequency() 和QueryPerformanceCounter()的返回值都存放在QuadPart上。

 

 

参考链接1

参考链接2


fopen()

函数原型:FILE * fopen(const char * path,const char * mode);

函数功能:打开一个文件

返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中。

  一般而言,打开文件后会作一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以一般在fopen()后作错误判断及处理。例如:

 

    if (( infile = fopen ( infilename, "rb" )) == NULL)//打开文件,用infile指向输入文件流
    {
          printf ( "Can't open %s\n", infilename );
          exit ( 1 );
    }

 

setvbuf()

功能:把缓冲区与流相关

原型: int setvbuf(FILE *stream, char *buf, int type, unsigned size);

参数:stream :指向流的指针 ;  buf : 期望缓冲区的地址;  type : 期望缓冲区的类型:  _IOFBF(满缓冲):当缓冲区为空时,从流读入数据。或者当缓冲区满时,向流写入数 据。  _IOLBF(行缓冲):每次从流中读入一行数据或向流中写入一行数据。  _IONBF(无缓冲):直接从流中读入数据或直接向流中写入数据,而没有缓冲区。  size : 缓冲区内字节的数量。


这个函数应该在打开流后,在任何对该流做输入输出前,立即调用.


fgetc()

功能:从流中读取字符

格式:int fgetc(FILE *stream);  

意为从文件指针stream指向的文件中读取一个字符。这个函数的返回值,是返回读取的一个字节。如果       读到文件末尾或者读取出错时返回EOF。

fputc(),与fgetc()相对应

例如:

 

 while (( c = fgetc ( infile )) != EOF )
        fputc ( c, outfile );
  

 

算法实际运行截图:

case1:

 


case2:

 


case3:




case4(正常测试):




case5:













 

分享到:
评论

相关推荐

    数据结构与算法分析—C语言描述.pd

    《数据结构与算法分析:C语言描述(原书第2版)》内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能、效率以及对运行时间分析的基础上考查了一些高级数据结构,从历史的角度...

    算法导论(part2)

    注重算法设计的效率,对所有的算法进行了仔细、精确的运行时间分析,有利于进一步改进算法。 三、本书的用法 本书对内容进行了精心的设计和安排,尽可能考虑到所有水平的读者。即使是初学计算机算法的人,也可以在...

    数据结构与算法分析——C语言描述.rar

    通过C程序的实现,着重阐述了抽象数据类型的概念,并对算法的效率、性能和运行时间进行了分析。 全书特点如下: ●专用一章来讨论算法设计技巧,包括贪婪算法、分治算法、动态规划、随机化算法以及回溯算法 ●介绍了...

    算法导论(part1)

    注重算法设计的效率,对所有的算法进行了仔细、精确的运行时间分析,有利于进一步改进算法。 三、本书的用法 本书对内容进行了精心的设计和安排,尽可能考虑到所有水平的读者。即使是初学计算机算法的人,也可以在...

    数据结构与算法分析:C语言描述(原书第2版).rar

    通过C程序的实现,着重阐述了抽象数据类型的概念,并对算法的效率、性能和运行时间进行了分析。 \r\n 全书特点如下: \r\n ●专用一章来讨论算法设计技巧,包括贪婪算法、分治算法、动态规划、随机化算法以及回溯...

    数据结构与算法分析—C语言描述

    书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能、效率以及对运行时间分析的基础上考查了一些高级数据结构,从历史的角度和近年的进展对数据结构的活跃领域进行了简要的概括。...

    算法设计与分析试卷.doc

    1.算法的时间复杂性是算法运行所需要的( )的量,这个量应该是只依赖于( )、( )和( )。 2.通常只考虑三种情况下的时间复杂性,实践表明可操作性最好且最有实用价值的是( )下的时间复杂性。 3.随机存取机...

    ConsoleApp1_C#_ConsoleApp1.exe_console_compassxuw_数据分析_

    此程序是在VS2017软件,利用C#语言编写了极坐标下牛顿法的潮流计算,对于任何节点只需要改动支路数据和节点数据即可,非常实用,并程序含有计算程序运行的时间,可进行算法时间效率分析。

    《妙趣横生的算法(C语言实现)》(杨峰 编著)

    4.12 记录程序的运行时间 4.13 十进制/二进制转化器 4.14 打印特殊图案 4.15 打印杨辉三角 4.16 复杂级数的前n项和 4.17 寻找矩阵中的“鞍点” 4.18 n阶勒让德多项式求解 4.19 递归反向输出字符串 4.20 一年中的第...

    大量批处理实用程序例程

    本资源由大量的实用批处理文件组成,删除.txt尾缀名双击即可直接使用,既是学习的模板也可以作为实用程序,如下为文件组成,涉及文件管理,系统,网络,小工具等等: 0-reaname 2000XP停止打印.bat BAT珍藏 dir.bat...

    实用万年历v5.9绿色特别版_包括农历节日.生肖.星座.黄历

    日期计算等均采用了现代高精度天文算法。日期范围:从公元前4600年至公元10000年,历时近一万五千年。包括公历、农历、回历、历史年号、公农历节日、节气、干支(生辰八字)、生肖、星座、出梅入梅、九九三伏、28...

    会计理论考试题

    A、应用程序停止运行 B、应用程序继续运行 C、应用程序图标就放到了任务栏上 D、单击该图标,窗口就还原了 5.窗口右上角的"X"按钮是___C___。 A、最小化 B、最大化 C、关闭 D、选择 6.为了以最佳方式、最少的重复,...

    实用万年历Sywnl(v6.28)

    日期计算等均采用了现代高精度天文算法。日期范围:从公元前4600年至公元10000年,历时近一万五千年。包括公历、农历、回历、历史年号、公农历节日、节气、干支(生辰八字)、生肖、星座、出梅入梅、九九三伏、28...

    浅谈关于能量管理系统

    这是对EM S 应用软件的源程序、画面和数据库进行改造, 调节改变有关算法的控制参数, 使运行人员可以直接在EM S 监视器画面上对状态估计和调度员潮流等模块计算的过程和计算的收敛精度进行控制。 3. 4 EMS 计算结果...

    python基于实现的推荐算法电影推荐系统带vue前后端分离+源代码+文档说明+论文+sql文件

    基于推荐算法的电影推荐系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在...

    python基于协同过滤算法实现的电影推荐系统带vue前后端分离+源代码+文档说明+论文+sql文件

    基于python和协同过滤算法的电影推荐系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。...

    计算机程序的正确定义

     为了一个程序运行,计算机加载程序代码,可能还要加载数据,从而初始化成一个开始状态,然后调用某种启动机制。在最低层上,这些是由一个引导序列开始的。  在大多数计算机中,操作系统例如视窗等,加载并且执行...

    计算机要学哪些东西----(还有附赠哦)

    运行时间存储管理 指针和引用 链接结构 栈、队列和哈希表的实现策略 图和树的实现策略 选择正确数据结构的策略 学习目标: 1. 讨论简单(primitive)数据类型和内置数据结构的表示和使用。 2. 描述主题列表中的...

    实用万年历Sywnl(v6.11)

    日期计算等均采用了现代高精度天文算法。日期范围:从公元前4600年至公元10000年,历时近一万五千年。包括公历、农历、回历、历史年号、公农历节日、节气、干支(生辰八字)、生肖、星座、出梅入梅、九九三伏、28...

    [详细完整版]操作系统题库.xls

    """记事本""实用程序的基本功能是____ A:文字处理" " 多个进程的实体能存在于同一内存中,在一段时间内都得到运行.这种性质称作进程的( ).C. 并发性" " 虚拟存储器所具有的基本特征是 —— 虚拟扩充,——部分装人 , ...

Global site tag (gtag.js) - Google Analytics