1、输出文件:一行,为D=A*B*C的第x行y列元素的值。算法设计及主要程序:问题分析:本题的主要考虑两个方面,一是稀疏矩阵的压缩储存,二是两个稀疏矩阵之间的乘法。其中最重要的一步又是矩阵的三元组乘法。任务一流程图(1).根据矩阵相乘的定义有:, 在经典算法中,不论,的值是否为0,都要进行一次乘法,而实际上,这两者有一个值值为0时,其积也为0。因此,在对稀疏矩阵进行相乘运算时,应该免去这种无效操作,为求Q的值,只需在M.data中和N.data中找到对应元素(即M.data中的j与N.data中的i相等的元素)相乘即可。(2).这样相乘的基本操作是:对于M中的每个元素M.datap(p=1,2,3
2、,M.da_num),找到N中所有满足M.datap.j= N.datap.i的元素N.dataq,求得其乘积。由于矩阵Q中每个元素的值是个累计和,这个乘积M.datap.vN.datap.v只是Qij的一部分。为了便于操作,应当对每个元素设计一个累计和变量,其初值为0,然后扫描数组M,求得相应元素的乘积并累加到适当的求和累计和的变量上。(3).两个稀疏矩阵相乘的乘积不一定为零矩阵。而两个即使矩阵的分量不为0,而乘积也可能是0。因此乘积矩阵Q中的元素是否为非零元,只有在求得其累加和后才能得知。由于Q中元素的行号和M中的行号一致,由此可对Q进行逐行处理,先求得累计求和的中间结果(Q的一行),然后
3、再压缩到Q.data中去。在解决了稀疏矩阵三元组相乘后,其储存结构也就迎刃而解了。只需够造一个三元组类记录三元组的属性(行号,列号,值),在构造矩阵类的时候加入属性举证行数,列数,三元组非零元总数,行优先标记数组就可。根据以上分析,程序设计流程图如上面所示:其中最重要的矩阵的三元组乘法程序如下:/-两稀疏矩阵相乘的主要算法,定义为友元函数-/Matrix Mult_Matrix(Matrix& m,Matrix& n) Matrix Q(m.row,n.col); int *ctemp=new intn.col; int tp,t_row,tr,t_col; if(m.col!=n.row)
4、couti=i;j=j;e=e; void set_data(int i,int j,int e) this-;/定义矩阵类-/class Matrix vector da; int ropsMAXSIZE; int row,col,da_num; Matrix() row=0; col=0; da_num=0; Matrix(int row,int col,int da_num=0)row=row;col=col;da_num=da_num;=da_num;+i) ropsi=-1; void put_data(data d) if(!da.size() put_rops(d.i,da.si
5、ze(); if(da.size()&d.i!=dada.size()-1.i) da.push_back(d); void put_rops(int m,int n) ropsm=n; int get_number(int m,int n)+i) if(dai.i=m&dai.j=n) return dai.e; return 0; friend Matrix Mult_Matrix(Matrix& n);/-/运行结果:本程序在Linux GCC和Windos SP2 VC+2008下均调试通过。其运行结果如下:程序结果分析: 分析算法的时间复杂度有如下结果:累加器ctemp初始化的效率为
6、O(A.da_num*B.da_num),求两矩阵相乘结果中的所有非零元的时间复杂度为O(M.col*N.col/N.row),进行压缩的时间复杂度为O(M.row*N.col),总的时间复杂度为O(M.row*N.col+M.col*N.col/N.row)。实验任务二:单词统计统计输入文件中出现的不同的单词个数以及每个单词出现的频率,并起将这些单词按照词典的顺序排列好输出到文件中。输入:以文件的形式记录程序中所需要的数据。输出:结果应该存放在一个文件中,该文件的第一行是不同的单词个数,从第二行开始则为每个单词和其相应的频率,单词与频率之间用空格符分割,单词需按字典顺序排列。算法设计与主要程
7、序段:本题的主要是单词的有序统计,主要难点在于如何设计高效的统计函数,达到广泛的统计要求(一般可统计数百万单词),首先是读入文件时的单词分割,然后是两个单词的比较(本题而言,可以重载“”和“”操作符),单词分割和两个单词的比较都比较简单,时间代价是线性的0(1),故不需要优化。只要是单词的统计上,如何去寻找好的数据结构和高效的算法。首先可以想到数组,数组的优点是其有序性,故重载“”和“”操作符时可以利用二分查找法插入位置,时间代价为0(log(n),但是在新的单词插入后,整个数组的序列会改变,这种元素移位操作却非常耗时,代价为O(n2),再加上数组对统计单词数具有容量限制(数组的大小必须实现分
8、配),就算用优化后的向量可以满足动态分配内存,但总的说来时间时间代价昂贵,不能采用。再次是链表,链表优点可以动态分配内存,对单词的统计量没有限制,缺点是没有好的方法来实现重载“”和“”操作符,这个代价是0(n2)。当然优化后的List在排序时可以小一点,但时间效代价仍然非常昂贵,也不能采用。考虑到前面两种数据结构各自的优缺点,可以直到数据结构中的二叉排序树(AVL)可以很好的解决动态储存空间的分配和插入查找,其时间代价为O(log(n),已经非常廉价,但AVL在实现重载“”和“”操作符只能单向二分,为此可以对节点进行红黑标记,实现双向二分查找。任务二流程图查找与插入问题解决后,接下来就是单词与
9、其个数之间的关系问题。利用红黑数时,不妨可采用每个节点5个域,分别标记前驱,后继,红黑标记,键(单词),码(单词个数)。这样的优点是可以将单词与其个数之间形成二元关系,即二元键值对。通过“=az=si)|(siAZ=si)&=s.size() +i; j=i; while(sj=sj)|(sj=sj)|(sj=39) +j; if(i=s.size() return false; for(;=j&=s.size(); if(si) si=si+-; temp.push_back(si); s=temp; return true;/-/单词计数数据结构map的选择: map counters;
10、int sum=0; string s; while(ins) if(changeWords(s) counterss+; sum+;进行单词统计的时候,只统计ASCII编码的单词,对于其他编码,如UNICLDE,GB2312,GBK,BIG5等编码的全角字母(占两个字节),全部滤过不做统计,对汉字及其他双字节的文字一律滤过,不做统计。算法设计主要是利用map中红黑树,实现键值对,一个单词(键)对应一个值(值),形成映射.在查找和插入时主要是红黑数的双向二分查找插入,效率为O(log(size_of_map),对于本程序的运用(统计量大约在10MB,1000000个单词以下来说,效率是可以接受
11、的)。如果需要进行更大的统计,则可以用hash表来实现编码。查找和插入时间效率为O(1)。但是编码和处理地址冲突的指令较多,所以在统计少量的单词时,反而没有map快,同时由于统计对单词是有序要求,hash技术对于保持有序上很难做到,故另外还需要设计排序方案,但排序本身也是一个很耗时的事情,因而本题目的最佳选择还是map。实验任务三:指针式时钟可视化的显一个指针式模拟时钟;可为程序设计一个美观大方的图标;通过菜单可以调整时间,定制指针式时钟的显示风格,比如指针、表盘的颜色、外形等,可以按照个人的兴趣进行其他的属性的扩展。主要设计思路和所涉及的类:本题是一个可视化编程问题,目前可视化编程工具比较多
12、,我采用的是比较流行的VC。对于题目要求的可视化,可以建一个SDI(单文档视图结构)程序,设计主要分为可视化和控件标准两部分。前一部分主要在Cview类中完成,后一部分主要在Cframe类中完成。其中可视化画图主要在OnDraw函数中添加代码实现。设计时首先是读取时间,现在读取时间的方式主要有从操作系统和网络远程读取,由于寝室上网不方便,我采用的是从操作系统中读取时间,然后由时间变量用三角函数转换得到各个指针的首末坐标,进而画出表盘,再添加计时器,每个一秒重新读取一次新时间,并更新表盘画面,这样就可以使闹钟动起来。各个控件的属性与响应函数可以自己在Cframe类中添加代码完成。按照以上的设计规
13、划,可以将整个任务分为以下三块:1读取时间,以及记录闹钟的时间等,设定定时器。2画出表盘时钟,实现美观大方的可视化。3附加功能,如闹钟,日列,备忘录等控件设计。对于第一块,先定义几个全局型变量extern bool ifon; /闹钟标记extern bool ifsound; /闹钟声音标记extern int h,m,s; /分别记录闹钟的时分秒再设计计时器,使之每一秒钟向系统读一次时间。代码如下:int CAlarmClockView:OnCreate(LPCREATESTRUCT lpCreateStruct) if (CFormView:OnCreate(lpCreateStruct
14、) = -1) return -1; / TODO: Add your specialized creation code here /设置时间步长为1s. SetTimer(1,1000,NULL);接下来将重操作系统读取的UNIX时间节转化为时分秒数字时钟。代码为:CTime Now=CTime:GetCurrentTime(); /读取操作系统的时间。m_tDate=Now;UpdateData(false);m_dDate.SetToday(&Now); /将UNIX时间节转化数字形式 CString s1,stime,ntime;stime.Format(%d:%02d:%02d,h
15、,m,s); /将闹钟时间格式化/将UNIX时间节转化为时分秒数字时钟,并格式化ntime.Format(,Now.GetHour(),Now.GetMinute(),Now.GetSecond();第二块,有了以上读出的系统时间后,就可以根据时间变量来画出此时刻的半盘,代码如下:/界面美观性的设计if (Now.GetHour()=11) s1=早上好,欢迎您使用Rolex情侣珍藏版AlarmClock! else if (Now.GetHour()SetTextColor(RGB(0,0,255);TextOut(90,15,s1); /为闹钟同时也设计界面 if(!ifon) m_Sta
16、tic1.ShowWindow(false); pDC-SetTextColor(RGB(255,0,0);TextOut(60,245,闹铃功能未启动); else m_Static1.ShowWindow(true);闹铃已启动,时间为+stime);SetTextColor(RGB(0,0,0);TextOut(300,230,现在时刻:Rectangle(365,255,465,270);SetTextColor(RGB(0,255,255);TextOut(300,255,ntime); CBrush br,br1; br.CreateSolidBrush(RGB(0,255,0);
17、SelectStockObject(NULL_PEN);SelectObject(&br); int l; l=int(double)Now.GetHour()+(double)Now.GetMinute()/60.0+(double)Now.GetSecond()/3600.0)/24.0*100);Rectangle(366,256,366+l,270); br1.CreateSolidBrush(RGB(255,255,255);br1); /画表盘 int nCenterX = 385; int nCenterY = 135; CString strDigits; int i,x,y;
18、 CSize size; CPen Pen(PS_SOLID,5,RGB(0,128,255); CPen *pOldPen=pDC-Pen);Ellipse(300,50,470,220); double Radians; for(i=1;iGetTextExtent(strDigits,strDigits.GetLength(); Radians = (double) i * 6.28 / 12.0; x=nCenterX-(size.cx/2)+(int)(double)72*sin(Radians); y=nCenterY-(size.cy/2)-(int)(double)72*cos
19、(Radians);TextOut( x, y, strDigits ); Radians=(double)Now.GetHour()+(double)Now.GetMinute()/60.0+(double)Now.GetSecond()/3600.0; /画表盘主要利用三角函数进行坐标变化。 Radians*=2*3.14159/12.0; CPen HourPen(PS_SOLID,5,RGB(233,233,15);HourPen);MoveTo(nCenterX,nCenterY);LineTo(nCenterX+(int)(double)(25)*sin(Radians),nCenterY-(int)(double)(25)*cos(Radians); /画时间指针 Radians=(double)Now.GetMinute()+(double)Now.GetSecond()/60.0; Radians*=2*3.14159/60.0; CPen MinutePen(PS_SOLID,3,RGB(0,0,255);MinutePen);LineTo(nCenterX+(int)(double)(40)*sin(Radians),nCenterY-(int)(do
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1