软考软件设计师数据结构学习C++合集.docx

上传人:b****1 文档编号:2029717 上传时间:2023-05-02 格式:DOCX 页数:69 大小:51.25KB
下载 相关 举报
软考软件设计师数据结构学习C++合集.docx_第1页
第1页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第2页
第2页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第3页
第3页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第4页
第4页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第5页
第5页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第6页
第6页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第7页
第7页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第8页
第8页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第9页
第9页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第10页
第10页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第11页
第11页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第12页
第12页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第13页
第13页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第14页
第14页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第15页
第15页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第16页
第16页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第17页
第17页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第18页
第18页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第19页
第19页 / 共69页
软考软件设计师数据结构学习C++合集.docx_第20页
第20页 / 共69页
亲,该文档总共69页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

软考软件设计师数据结构学习C++合集.docx

《软考软件设计师数据结构学习C++合集.docx》由会员分享,可在线阅读,更多相关《软考软件设计师数据结构学习C++合集.docx(69页珍藏版)》请在冰点文库上搜索。

软考软件设计师数据结构学习C++合集.docx

软考软件设计师数据结构学习C++合集

数据结构学习(C++)(合集)

题外话:

先前有一篇文章叫《用C++模板描述的链表、栈、队列(声明与实现)》,当时是第一次发表文章(我才注册没几天),很不成熟,改了又改不说,还弄的老长,不利于阅读。

于是我重写了一下,并且想做成一个系列,这从我的标题可以看出来。

好,言归正传。

本篇为后面一系列文章的序言,旨在说明写作的目的,以及写作的风格;或者说是为自己可能的错误,预先给个托词。

如果您不想听我在这废话,请跳过本篇,直接阅读后面的文章。

但是这样,我不能保证,您在阅读的同时,不会骂我白痴。

为什么写这些文章

这些文章可以说是《数据结构(用面向对象方法与C++描述)》这本书的读书笔记,但也不完全是。

数据结构是计算机专业必修课——几乎每个计算机专业的学生都会推崇他的重要;同时,也是其他专业转修计算机专业的一个难点。

从学习的角度来说,严蔚敏的《数据结构(C语言版)》是本不错的书。

但是,C语言不是描述的理想工具。

《数据结构(C语言版)》的前言里是这样说的:

“虽然C语言不是抽象数据类型的理想描述工具,但鉴于目前和近一、二年内,……并增添了C++语言的引用调用参数传递方式等,构成了一个类C描述语言。

从抽象数据类型的定义——一个数学模型以及定义在该模型上的一组操作——可以看出,面向对象语言中类的概念和这个定义很接近,加之C语言的普及,用C++来描述于是就成了顺理成章的事情。

于是,清华在2002年的考研参考书目中对《数据结构》的参考书做了改变,使用《数据结构(用面向对象方法与C++描述)》(殷人昆等编著,ISBN7-302-03405-2/TP1845)作为参考书,而实际上考的也是(废话,不是那叫误导)。

坦白的讲,原书把教学目的和提供实例的目的搞混了,结果是个四不象:

作为教科书,条理不清晰;提供各个方法的实现,也不是很实用,相反,重复建设太多。

至于错误,可能有些是笔误,比如少个友元声明了,不是继承而使用别的类的成员函数没有指明了;还有一些,就是考虑不够周全。

不管怎么说,现在不是挑书的时候,你想考清华的计算机专业研究生吗,这本书是你不二的选择。

我发现读懂此书的最好方法,就是自己按照书上的思路,以及实际应用的分析,自己重新实现各种抽象数据类型。

这样做还有一个好处,为自己将来积累一点财富。

我的写作风格

编译器我选用的是VC6,因此,我不保证我提供的代码在别的编译器也能通过——从头到尾只使用了iostream.h,没有任何别的库,当然更没有MFC,标准的C++代码应该没什么问题。

全部是手工完成的代码,没有使用ClassWizard,主要是不喜欢那些乱七八糟的预处理和注释。

这样完成之后,发现C++的声明和实现分开xx.h+xx..ccp这种文档结构并不招人喜欢——很乱。

于是我采用了单工程单cpp的结构,就是一个工程只有一个cpp文件,放main(),其他的部分都是头文件,声明和实现放在一起——其实这是违反C++规范的,C++要求函数必须声明原型,实际上,我觉得这很罗嗦(我这是典型的C后遗症,以前用TC时为了不声明原型,把函数都放到main()前面),声明一下原型,我认为这和设定密码需要确认一个道理。

由于使用的IDE环境,把声明单独集中起来作为一个文件已经没有必要——ClassView窗口很好用,就因为如此,我几乎从来不去看类的声明文件。

除非你提供的是一个库,在你的工程中单独的声明文件已经不是必须的了。

当然,这里的前提是从一个空的工程建立你的项目。

如果你使用了AppWizard,我很难想象不使用ClassWizard的。

因为这时文档的结构已经确定了,你所做的实际上是在修修补补。

什么人适合读这些文章

●        刚开始从C过渡到C++的人,看完这些后,会体会到C++的新特性。

●        和我一样研读那本黄皮书的人,希望看完之后能更好的理解和学习。

●        从未编写过超过1000行代码程序的人,这样我们才能达到共鸣。

因为我们从来不使用工具和库文件,做的事都是在编程老手看来很蠢的事。

一些约定

假定你使用的是VC6,先建立一个Win32ConsoleApplication的emptyproject。

后面将陆续往这个工程中添加文件(就是将后面介绍的每一个文件都添加进去,不然到时候找不到xx.h不要埋怨),每一个#ifndefxx_H~#endif和其中的部分为一个头文件,文件名为xx.h。

例如:

#ifndefList_H

#defineList_H

……

#endif

这一大块为一个文件,文件名为List.h

 

数据结构学习(C++)—队列应用(事件驱动模拟)

我看的两本教科书(《数据结构(C语言版)》还有这本黄皮书)都是以这个讲解队列应用的,而且都是银行营业模拟(太没新意了)。

细比较,这两本书模拟的银行营业的方式还是不同的。

1997版的《数据结构(C语言版)》的银行还是老式的营业模式(毕竟是1997年的事了),现在的很多地方还是这种营业模式——几个窗口同时排队。

这种方式其实不太合理,经常会出现先来的还没有后来的先办理业务(常常前面一个人磨磨蹭蹭,别的队越来越短,让你恨不得把前面那人干掉)。

1999版的这本黄皮书的银行改成了一种挂牌的营业方式,每个来到的顾客发一个号码,如果哪个柜台空闲了,就叫号码最靠前的顾客来办理业务;如果同时几个柜台空闲,就按照一种法则来决定这几个柜台叫号的顺序(最简单的是按柜台号码顺序)。

这样,就能保证顾客按照先来后到的顺序接受服务——因为大家排在一个队里。

这样的营业模式我在北京的西直门工商银行见过,应该说这是比较合理的一种营业模式。

不过,在本文中最重要的是,这样的营业模式比较好模拟(一个队列总比N个队列好操作)。

原书的这部分太难看了,我看的晕晕的,我也不知道按照原书的方法能不能做出来,因为我没看懂(旁白:

靠,你小子这样还来现眼)。

我按照实际情况模拟,实现如下:

#ifndefSimulation_H

#defineSimulation_H

 

#include

#include

#include

 

classTeller

{

public:

inttotalCustomerCount;

inttotalServiceTime;

intfinishServiceTime;

Teller():

totalCustomerCount(0),totalServiceTime(0),

finishServiceTime(0){}

};

//#definePRINTPROCESS

classSimulation

{

public:

Simulation()

{

cout<

cout<<"柜台数量:

";cin>>tellerNum;

cout<<"营业时间:

";cin>>simuTime;

cout<<"两个顾客来到的最小间隔时间:

";cin>>arrivalLow;

cout<<"两个顾客来到的最大间隔时间:

";cin>>arrivalHigh;

cout<<"柜台服务最短时间:

";cin>>serviceLow;

cout<<"柜台服务最长时间:

";cin>>serviceHigh;

arrivalRange=arrivalHigh-arrivalLow+1;

serviceRange=serviceHigh-serviceLow+1;

srand((unsigned)time(NULL));

}

 

Simulation(inttellerNum,intsimuTime,intarrivalLow,intarrivalHigh,intserviceLow,intserviceHigh)

:

tellerNum(tellerNum),simuTime(simuTime),arrivalLow(arrivalLow),arrivalHigh(arrivalHigh),

serviceLow(serviceLow),serviceHigh(serviceHigh),

arrivalRange(arrivalHigh-arrivalLow+1),serviceRange(serviceHigh-serviceLow+1)

{srand((unsigned)time(NULL));}

 

voidInitialize()

{

curTime=nextTime=0;

customerNum=customerTime=0;

for(inti=1;i<=tellerNum;i++)

{

tellers[i].totalCustomerCount=0;

tellers[i].totalServiceTime=0;

tellers[i].finishServiceTime=0;

}

customer.MakeEmpty();

}

 

voidRun()

{

Initialize();

NextArrived();

#ifdefPRINTPROCESS

cout<

cout<<"tellerID";

for(intk=1;k<=tellerNum;k++)cout<<"TELLER"<

cout<

#endif

for(curTime=0;curTime<=simuTime;curTime++)

{

if(curTime>=nextTime)

{

CustomerArrived();

NextArrived();

}

#ifdefPRINTPROCESS

cout<<"Time:

"<

#endif

for(inti=1;i<=tellerNum;i++)

{

if(tellers[i].finishServiceTime

if(tellers[i].finishServiceTime==curTime&&!

customer.IsEmpty())

{

intt=NextService();

#ifdefPRINTPROCESS

cout<<''<

#endif

CustomerDeparture();

tellers[i].totalCustomerCount++;

tellers[i].totalServiceTime+=t;

tellers[i].finishServiceTime+=t;

 

}

#ifdefPRINTPROCESS

elsecout<<"";

#endif

}

#ifdefPRINTPROCESS

cout<

#endif

}

PrintResult();

}

 

voidPtintSimuPara()

{

cout<

cout<<"柜台数量:

"<

"<

cout<<"两个顾客来到的最小间隔时间:

"<

cout<<"两个顾客来到的最大间隔时间:

"<

cout<<"柜台服务最短时间:

"<

cout<<"柜台服务最长时间:

"<

}

 

voidPrintResult()

{

inttSN=0;

longtST=0;

cout<

cout<<"-------------模拟结果-------------------";

cout<

for(inti=1;i<=tellerNum;i++)

{

cout<<"TELLER"<

cout<<''<

cout<<''<

cout<<'';

if(tellers[i].totalCustomerCount)

cout<<(float)tellers[i].totalServiceTime/(float)tellers[i].totalCustomerCount;

elsecout<<0;

cout<<""<

}

cout<<"TOTAL"<

if(tSN)cout<<(float)tST/(float)tSN;elsecout<<0;

cout<<""<

cout<<"CustomerNumber:

"<

"<

cout<<"CustomerWaitTime:

"<

";

if(tSN)cout<<(float)customerTime/(float)tSN;elsecout<<0;

cout<

}

 

private:

inttellerNum;

intsimuTime;

intcurTime,nextTime;

intcustomerNum;

longcustomerTime;

intarrivalLow,arrivalHigh,arrivalRange;

intserviceLow,serviceHigh,serviceRange;

Tellertellers[21];

Queuecustomer;

voidNextArrived()

{

nextTime+=arrivalLow+rand()%arrivalRange;

}

 

intNextService()

{

returnserviceLow+rand()%serviceRange;

}

 

voidCustomerArrived()

{

customerNum++;

customer.EnQueue(nextTime);

}

 

voidCustomerDeparture()

{

customerTime+=(long)curTime-(long)customer.DeQueue();

}

 

};

 

#endif

几点说明

●        Run()的过程是这样的:

curTime是时钟,从开始营业计时,自然流逝到停止营业。

当顾客到的事件发生时(顾客到时间等于当前时间,小于判定是因为个别时候顾客同时到达——输入arrivalLow=0的情况,而在同一时间,只给一个顾客发号码),给这个顾客发号码(用顾客到时间标示这个顾客,入队,来到顾客数增1)。

当柜台服务完毕时(柜台服务完时间等于当前时间),该柜台服务人数增1,服务时间累加,顾客离开事件发生,下一个顾客到该柜台。

因为柜台开始都是空闲的,所以实际代码和这个有点出入。

最后,停止营业的时候,停止发号码,还在接受服务的顾客继续到服务完,其他还在排队的就散伙了。

●        模拟结果分别是:

各个柜台的服务人数、服务时间、平均服务时间,总的服务人数、服务时间、平均服务时间,来的顾客总数、没被服务的数目(来的太晚了)、接受服务顾客总等待时间、平均等待时间。

●        这个算法效率是比较低的,实际上可以不用队列完成这个模拟(用顾客到时间推动当前时钟,柜台直接公告服务完成时间),但这样就和实际情况有很大差别了——出纳员没等看见人就知道什么时候完?

虽然结果是一样的,但是理解起来很莫名其妙,尤其是作为教学目的讲解的时候。

当然了,实际中为了提高模拟效率,本文的这个算法是不值得提倡的。

●        注释掉的#definePRINTPROCESS,去掉注释符后,在运行模拟的时候,能打印出每个时刻柜台的服务情况(第几个顾客,顾客到达时间,接受服务时间),但只限4个柜台以下,多了的话屏幕就满了(格式就乱了)。

【后记】本来我没打算写这篇,后来,当我开始实现模拟的时候,竟欲罢不能了。

这是数据结构这本书中第一个实际应用的例子,而且也有现实意义。

你可以看出各个柜台在不同的业务密度下的工作强度(要么给哪个柜台出纳员发奖金,要么轮换柜台),各种情况下顾客的等待时间(人都是轮到自己就不着急了),还有各种情况下设立几个柜台合理(很少的空闲时间,很短的等待时间,几乎为零的未服务人数)。

例如这样:

for(inti=1;i<16;i++)

{

Simulationa(i,240,1,4,8,15);

a.Run();

}

你模拟一下就会得出,在不太繁忙的银行,4~5个柜台是合适的——现在的银行大部分都是这样的。

 

数据结构学习(C++)—单链表(定义与实现)

节点类

#ifndefNode_H

#defineNode_H

 

templateclassNode//单链节点类

{

public:

Typedata;

Node*link;

Node():

data(Type()),link(NULL){}

Node(constType&item):

data(item),link(NULL){}

Node(constType&item,Node*p):

data(item),link(p){}

};

 

#endif

【说明】因为数据结构里用到这个结构的地方太多了,如果用原书那种声明友元的做法,那声明不知道要比这个类的本身长多少。

不如开放成员,事实上,这种结构只是C中的struct,除了为了方便初始化一下,不需要任何的方法,原书那是画蛇添足。

下面可以看到,链表的public部分没有返回Node或者Node*的函数,所以,别的类不可能用这个开放的接口对链表中的节点操作。

【重要修改】原书的缺省构造函数是这样的Node():

data(NULL),link(NULL){}  。

我原来也是照着写的,结果当我做扩充时发现这样是不对的。

当Type为结构而不是简单类型(int、……),不能简单赋NULL值。

这样做使得定义的模板只能用于很少的简单类型。

显然,这里应该调用Type的缺省构造函数。

 这也要求,用在这里的类一定要有缺省构造函数。

在下面可以看到构造链表时,使用了这个缺省构造函数。

当然,这里是约定带表头节点的链表,不带头节点的情况请大家自己思考。

【闲话】请不要对int*p=newint

(1);这种语法有什么怀疑,实际上int也可以看成一种class。

单链表类

#ifndefList_H

#defineList_H

 

#ifndefTURE

#defineTURE1

#endif

#ifndefFALSE

#defineFALSE0

#endif

typedefintBOOL;

 

#include"Node.h"

 

templateclassList//单链表定义

{

//基本上无参数的成员函数操作的都是当前节点,即current指的节点

//认为表中“第1个节点”是第0个节点,请注意,即表长为1时,最后一个节点是第0个节点

public:

List(){first=current=last=newNode;prior=NULL;}

~List(){MakeEmpty();deletefirst;}

 

voidMakeEmpty()//置空表

{

Node*q;

while(first->link!

=NULL)

{

q=first->link;

first->link=q->link;

deleteq;

}

Initialize();

}

BOOLIsEmpty()

{

if(first->link==NULL)

{

Initialize();

returnTURE;

}

elsereturnFALSE;

}

intLength()const//计算带表头节点的单链表长度

{

Node*p=first->link;

intcount=0;

while(p!

=NULL)

{

p=p->link;

count++;

}

returncount;

}

 

Type*Get()//返回当前节点的数据域的地址

{

if(current!

=NULL)return¤t->data;

elsereturnNULL;

}

 

BOOLPut(Typeconst&value)//改变当前节点的data,使其为value

{

if(current!

=NULL)

{

current->data=value;

returnTURE;

}

elsereturnFALSE;

}

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

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2