程序设计方法专题实验报告Word文档下载推荐.docx

上传人:b****7 文档编号:22357627 上传时间:2023-02-03 格式:DOCX 页数:25 大小:309.22KB
下载 相关 举报
程序设计方法专题实验报告Word文档下载推荐.docx_第1页
第1页 / 共25页
程序设计方法专题实验报告Word文档下载推荐.docx_第2页
第2页 / 共25页
程序设计方法专题实验报告Word文档下载推荐.docx_第3页
第3页 / 共25页
程序设计方法专题实验报告Word文档下载推荐.docx_第4页
第4页 / 共25页
程序设计方法专题实验报告Word文档下载推荐.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

程序设计方法专题实验报告Word文档下载推荐.docx

《程序设计方法专题实验报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《程序设计方法专题实验报告Word文档下载推荐.docx(25页珍藏版)》请在冰豆网上搜索。

程序设计方法专题实验报告Word文档下载推荐.docx

输出文件:

一行,为D=A*B*C的第x行y列元素的值。

算法设计及主要程序:

问题分析:

本题的主要考虑两个方面,一是稀疏矩阵的压缩储存,二是两个稀疏矩阵之间的乘法。

其中最重要的一步又是矩阵的三元组乘法。

任务一流程图

(1).根据矩阵相乘的定义有:

在经典算法中,不论

的值是否为0,都要进行一次乘法,而实际上,这两者有一个值值为0时,其积也为0。

因此,在对稀疏矩阵进行相乘运算时,应该免去这种无效操作,为求Q的值,只需在M.data中和N.data中找到对应元素(即M.data中的j与N.data中的i相等的元素)相乘即可。

(2).这样相乘的基本操作是:

对于M中的每个元素M.data[p](p=1,2,3……,M.da_num),找到N中所有满足M.data[p].j=N.data[p].i的元素N.data[q],求得其乘积。

由于矩阵Q中每个元素的值是个累计和,这个乘积M.data[p].v×

N.data[p].v只是Q[i][j]的一部分。

为了便于操作,应当对每个元素设计一个累计和变量,其初值为0,然后扫描数组M,求得相应元素的乘积并累加到适当的求和累计和的变量上。

(3).两个稀疏矩阵相乘的乘积不一定为零矩阵。

而两个即使矩阵的分量不为0,而乘积也可能是0。

因此乘积矩阵Q中的元素是否为非零元,只有在求得其累加和后才能得知。

由于Q中元素的行号和M中的行号一致,由此可对Q进行逐行处理,先求得累计求和的中间结果(Q的一行),然后再压缩到Q.data中去。

在解决了稀疏矩阵三元组相乘后,其储存结构也就迎刃而解了。

只需够造一个三元组类记录三元组的属性(行号,列号,值),在构造矩阵类的时候加入属性举证行数,列数,三元组非零元总数,行优先标记数组就可。

根据以上分析,程序设计流程图如上面所示:

其中最重要的矩阵的三元组乘法程序如下:

//---------两稀疏矩阵相乘的主要算法,定义为友元函数--------------//

MatrixMult_Matrix(Matrix&

m,Matrix&

n){

MatrixQ(m.row,n.col);

int*ctemp=newint[n.col];

inttp,t_row,tr,t_col;

if(m.col!

=n.row){

cout<

<

"

两矩阵不能相乘!

endl;

exit

(1);

}

if(m.da_num*n.da_num){//若果结果为非零矩阵

for(inti=0;

i!

=m.row;

++i){//逐行相乘,得到Q各行的的结果

for(intii=0;

ii!

=n.col;

++ii)

ctemp[ii]=0;

//每次temp都必须初始话为

Q.rops[i]=Q.da_num;

//查找到一行的首个非零元素,找到就返回其值,否值就返回-,表示该行全为,不用相乘

//找到该行的最后一个非零元的下一个元素位置,注意,若该行为行(全为)的话,那么就该行首个非零元素

//就和最后一个非零元的下一个元素位置相同,那么直接跳出循环,不用相乘

if(i!

=m.row-1)

tp=m.rops[i+1];

else

tp=m.da_num;

for(intj=m.rops[i];

j!

=tp;

++j){//一行的各个三元组分别相乘累加

t_row=m.da[j].j;

//该行某个元素找到与其相对应Matrix&

n的行的首个非零元

if(t_row!

=n.row-1)//该行某个元素找到与其相对应Matrix&

n的行的最后个非零元的下一位置

tr=n.rops[t_row+1];

else

tr=n.da_num;

//如果中对应的Matrix&

n行不是行,则相乘累加

for(intk=n.rops[t_row];

(k+1)&

&

k!

=tr;

++k){

t_col=n.da[k].j;

//找到结果所在列号

ctemp[t_col]+=m.da[j].e*n.da[k].e;

//对应的行号和列号相等的元素相加后累加

}//fork;

}//求得Q中第i行的非零元。

//压入储存三元组结果

for(t_col=0;

t_col!

=Q.col;

++t_col)

if(ctemp[t_col]){

Q.da_num++;

dataDA(i,t_col,ctemp[t_col]);

Q.da.push_back(DA);

}

}

delete[]ctemp;

returnQ;

}

//-------------------------------------------------------------//

根据稀疏矩阵相乘算法的要求与题意,定义三元组数据类和矩阵类如下:

//--------定义数据类,储存三元组数据---------//

classdata{

public:

inti,j;

inte;

data(inti=0,intj=0,inte=0){

this->

i=i;

j=j;

e=e;

voidset_data(inti,intj,inte){

this->

};

//-------—————定义矩阵类--------------//

classMatrix{

vector<

data>

da;

introps[MAXSIZE];

introw,col,da_num;

Matrix(){

row=0;

col=0;

da_num=0;

Matrix(introw,intcol,intda_num=0){

row=row;

col=col;

da_num=da_num;

=da_num;

++i)

rops[i]=-1;

voidput_data(datad){

if(!

da.size())

put_rops(d.i,da.size());

if(da.size()&

d.i!

=da[da.size()-1].i)

da.push_back(d);

voidput_rops(intm,intn){

rops[m]=n;

intget_number(intm,intn){

++i){

if(da[i].i==m&

da[i].j==n)

returnda[i].e;

return0;

friendMatrixMult_Matrix(Matrix&

n);

//---------------------------------------------------------------//

运行结果:

本程序在LinuxGCC和WindosSP2VC++2008下均调试通过。

其运行结果如下:

程序结果分析:

分析算法的时间复杂度有如下结果:

累加器ctemp初始化的效率为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)。

实验任务二:

单词统计

统计输入文件中出现的不同的单词个数以及每个单词出现的频率,并起将这些单词按照词典的顺序排列好输出到文件中。

输入:

以文件的形式记录程序中所需要的数据。

输出:

结果应该存放在一个文件中,该文件的第一行是不同的单词个数,从第二行开始则为每个单词和其相应的频率,单词与频率之间用空格符分割,单词需按字典顺序排列。

算法设计与主要程序段:

本题的主要是单词的有序统计,主要难点在于如何设计高效的统计函数,达到广泛的统计要求(一般可统计数百万单词),首先是读入文件时的单词分割,然后是两个单词的比较(本题而言,可以重载“<

”和“=”操作符),单词分割和两个单词的比较都比较简单,时间代价是线性的0

(1),故不需要优化。

只要是单词的统计上,如何去寻找好的数据结构和高效的算法。

首先可以想到数组,数组的优点是其有序性,故重载“<

”和“=”操作符时可以利用二分查找法插入位置,时间代价为0(log(n)),但是在新的单词插入后,整个数组的序列会改变,这种元素移位操作却非常耗时,代价为O(n^2),再加上数组对统计单词数具有容量限制(数组的大小必须实现分配),就算用优化后的向量可以满足动态分配内存,但总的说来时间时间代价昂贵,不能采用。

再次是链表,链表优点可以动态分配内存,对单词的统计量没有限制,缺点是没有好的方法来实现重载“<

”和“=”操作符,这个代价是0(n^2)。

当然优化后的List在排序时可以小一点,但时间效代价仍然非常昂贵,也不能采用。

考虑到前面两种数据结构各自的优缺点,可以直到数据结构中的二叉排序树(AVL)可以很好的解决动态储存空间的分配和插入查找,其时间代价为O(log(n)),已经非常廉价,但AVL在实现重载“<

”和“=”操作符只能单向二分,为此可以对节点进行红黑标记,实现双向二分查找。

任务二流程图

查找与插入问题解决后,接下来就是单词与其个数之间的关系问题。

利用红黑数时,不妨可采用每个节点5个域,分别标记前驱,后继,红黑标记,键(单词),码(单词个数)。

这样的优点是可以将单词与其个数之间形成二元关系,即二元键值对。

通过“<

”和“=”操作符运算,若一个单词(键)已经存在,只需将它的码值加1,若不存在,就在双向二分得到的位置插入新的结点,得到新的键值对。

当然,要实现一颗完好的红黑数是比较麻烦的,可以采用STL中对红黑优化过后的map。

经过以上分析,程序设计流程图如上所示:

其中单词分割程序为:

//--------------------将字符串转换成为单词----------------------//

boolchangeWords(string&

s){

stringtemp;

inti=0;

intj;

while(!

((s[i]>

='

a'

'

z'

>

=s[i])||(s[i]>

A'

Z'

=s[i]))&

=s.size())

++i;

j=i;

while(((s[j]>

=s[j])||(s[j]>

=s[j])||(s[j]==39)))

++j;

if(i==s.size())

returnfalse;

for(;

=j&

=s.size();

if(s[i]<

s[i]=s[i]+'

-'

;

temp.push_back(s[i]);

s=temp;

returntrue;

//--------------------------------------------------------------//

单词计数数据结构map的选择:

map<

string,int>

counters;

intsum=0;

strings;

while(in>

s){

if(changeWords(s)){

counters[s]++;

sum++;

进行单词统计的时候,只统计ASCII编码的单词,对于其他编码,如UNICLDE,GB2312,GBK,BIG5等编码的全角字母(占两个字节),全部滤过不做统计,对汉字及其他双字节的文字一律滤过,不做统计。

算法设计主要是利用map中红黑树,实现键值对,一个单词(键)对应一个值(值),形成映射.在查找和插入时主要是红黑数的双向二分查找插入,效率为O(log(size_of_map)),对于本程序的运用(统计量大约在10MB,1000000个单词以下来说,效率是可以接受的)。

如果需要进行更大的统计,则可以用hash表来实现编码。

查找和插入时间效率为O

(1)。

但是编码和处理地址冲突的指令较多,所以在统计少量的单词时,反而没有map快,同时由于统计对单词是有序要求,hash技术对于保持有序上很难做到,故另外还需要设计排序方案,但排序本身也是一个很耗时的事情,因而本题目的最佳选择还是map。

实验任务三:

指针式时钟

可视化的显一个指针式模拟时钟;

可为程序设计一个美观大方的图标;

通过菜单可以调整时间,定制指针式时钟的显示风格,比如指针、表盘的颜色、外形等,可以按照个人的兴趣进行其他的属性的扩展。

主要设计思路和所涉及的类:

本题是一个可视化编程问题,目前可视化编程工具比较多,我采用的是比较流行的VC++。

对于题目要求的可视化,可以建一个SDI(单文档视图结构)程序,设计主要分为可视化和控件标准两部分。

前一部分主要在Cview类中完成,后一部分主要在Cframe类中完成。

其中可视化画图主要在OnDraw函数中添加代码实现。

设计时首先是读取时间,现在读取时间的方式主要有从操作系统和网络远程读取,由于寝室上网不方便,我采用的是从操作系统中读取时间,然后由时间变量用三角函数转换得到各个指针的首末坐标,进而画出表盘,再添加计时器,每个一秒重新读取一次新时间,并更新表盘画面,这样就可以使闹钟动起来。

各个控件的属性与响应函数可以自己在Cframe类中添加代码完成。

按照以上的设计规划,可以将整个任务分为以下三块:

1.读取时间,以及记录闹钟的时间等,设定定时器。

2.画出表盘时钟,实现美观大方的可视化。

3.附加功能,如闹钟,日列,备忘录等控件设计。

对于第一块,先定义几个全局型变量

externboolifon;

//闹钟标记

externboolifsound;

//闹钟声音标记

externinth,m,s;

//分别记录闹钟的时分秒

再设计计时器,使之每一秒钟向系统读一次时间。

代码如下:

intCAlarmClockView:

:

OnCreate(LPCREATESTRUCTlpCreateStruct)

{

if(CFormView:

OnCreate(lpCreateStruct)==-1)

return-1;

//TODO:

Addyourspecializedcreationcodehere

//设置时间步长为1s.

SetTimer(1,1000,NULL);

接下来将重操作系统读取的UNIX时间节转化为时分秒数字时钟。

代码为:

CTimeNow=CTime:

GetCurrentTime();

//读取操作系统的时间。

m_tDate=Now;

UpdateData(false);

m_dDate.SetToday(&

Now);

//将UNIX时间节转化数字形式

CStrings1,stime,ntime;

stime.Format("

%d:

%02d:

%02d"

h,m,s);

//将闹钟时间格式化

//将UNIX时间节转化为时分秒数字时钟,并格式化

ntime.Format("

Now.GetHour(),Now.GetMinute(),Now.GetSecond());

第二块,有了以上读出的系统时间后,就可以根据时间变量来画出此时刻的半盘,代码如下:

//界面美观性的设计

if(Now.GetHour()<

=11)s1="

早上好,欢迎您使用Rolex情侣珍藏版AlarmClock!

elseif(Now.GetHour()<

=13)s1="

中午好,欢迎您使用Rolex情侣珍藏版AlarmClock!

=18)s1="

下午好,欢迎您使用Rolex情侣珍藏版AlarmClock!

elses1="

晚上好,欢迎您使用Rolex情侣珍藏版AlarmClock!

pDC->

SetTextColor(RGB(0,0,255));

TextOut(90,15,s1);

//为闹钟同时也设计界面

if(!

ifon)

{

m_Static1.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);

CBrushbr,br1;

br.CreateSolidBrush(RGB(0,255,0));

SelectStockObject(NULL_PEN);

SelectObject(&

br);

intl;

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);

//画表盘

intnCenterX=385;

intnCenterY=135;

CStringstrDigits;

inti,x,y;

CSizesize;

CPenPen(PS_SOLID,5,RGB(0,128,255));

CPen*pOldPen=pDC->

Pen);

Ellipse(300,50,470,220);

doubleRadians;

for(i=1;

i<

=12;

i++)

strDigits.Format("

%d"

i);

size=pDC->

GetTextExtent(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(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;

CPenHourPen(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;

CPenMinutePen(PS_SOLID,3,RGB(0,0,255));

MinutePen);

LineTo(nCenterX+(int)((double)(40)*sin(Radians)),nCenterY-(int)((do

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 电子电路

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1