数据结构与算法分析 C++描述(第3版) 习题2.8 详尽分析

数据结构与算法分析 C++描述(第3版) 习题2.8 详尽分析

Data Structures and Algorithm Analysis In C++ Third Edition By Mark Allen Weiss 转载请注明出处及作者:九天雁翎

a:因为12很明显,所以不证明了。

至于算法3,可以用数学归纳法证明,x详细证明如下:

1.n=1时,a[0]=1,都是100%,成立;

2.n=2时,

for(i = 1; i < n; ++i)

swap (a[i],a[ randInt(0,i)]);

第一次循环,当i=1时,此时a[0]=1,a[i]=a[1]

randInt(0,1)50%机会为050%机会为1,所以,swap(a[1],a[0])的机会为50%,即,序列为0,1; 1,0几率都为50%。 成立

3. n=3时,第二次循环时,当i=2时,此时有两种可能,原序列为0,1; 1,0的几率各为50%randInt(0,2)可能为0,1,2的几率各位1/3.此时,原序列为0,1,randInt(0,2)0,那么此序列经过swap(a[2],a[0]),最后序列为2,1,0,此序列的可能性为(1/2)*(1/3)=1/6; 同理易得,最后此序列为

210, 021, 012, 201, 120, 102的几率各位1/6,而此序列的所有排列可能为<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 15pt; HEIGHT: 17.25pt" type="#_x0000_t75"><imagedata chromakey="white" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.png"></imagedata></shape>= 3 * 2 = 6,所以 此时成立.

4.假设此命题在n = k时成立,那么就是说,k前面序列共有序列<shape id="_x0000_i1025" style="WIDTH: 20.25pt; HEIGHT: 26.25pt" type="#_x0000_t75"><imagedata chromakey="white" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image003.png"></imagedata></shape>种,且所有序列的几率为1/<shape id="_x0000_i1025" style="WIDTH: 20.25pt; HEIGHT: 26.25pt" type="#_x0000_t75"><imagedata chromakey="white" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image003.png"></imagedata></shape>.

5.n=k+1,k+1次循环时,前面序列正好为n=k时的情况,此时i = k. randInt(0,k)共可能为0~k,k+1种可能。所以以前的每个可能序列在置换后有k+1种可能,而以前共有k种等可能序列,那么最后可能的序列为k*(k+1)种可能,并且,因为原序列为等可能的,每个等可能序列产生的序列都是k+1种,所以最后的序列也是等可能的。而当n=k+1时,应该共有<shape id="_x0000_i1025" style="WIDTH: 33.75pt; HEIGHT: 26.25pt" type="#_x0000_t75"><imagedata chromakey="white" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image005.png"></imagedata></shape>=(k+1)*k种,所以,此命题得证。

即算法3产生的也是等置换序列。

这里最后要说明的是,证明时默认地利用了一个命题,

当原序列为互不相等的等可能序列时,新加入一个与原来序列任何数值都不相等的数值,无论这个数值放在原序列的哪个位置,都不可能使原不相等的序列相等,说的好复杂啊-_-!

基本就是这样,210, 021, 012, 201, 120, 102,这是你加入一个新的数值3,无论你把3插入序列的哪个位置,因为原来序列的排列不相等,所以,他们还是不会相等,这样,才保证了最后k个序列的k+1种可能都不相等,不会重复。

算法分析答案说的很详细,可以参考答案,即第一个算法为O(<shape id="_x0000_i1025" style="WIDTH: 44.25pt; HEIGHT: 16.5pt" type="#_x0000_t75"><imagedata chromakey="white" o:title="" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtmlclip1/01/clip_image007.png"></imagedata></shape>),第二个算法为ONlogN,第三个为线性。

实际算法的实现如下:

#include "jtianling/jtianling.h"

#include "boost/dynamic_bitset.hpp"

using namespace std;

//2.8题目中假设存在的随机数生成器

//根据其定义,此算法生成从ij的随机数,而且包括边界i,j.i=<n<=j

int randInt(int i, int j)

{

//确保i<j,不然就交换

if(i > j)

{

int temp = i;

i = j;

j = temp;

}

//确保范围正确

return rand()%(j-i+1) + i;

}

//算法,算法描述如题目.8所示,根据习惯,不对arr[]的大小做任何检验

//调用此函数的人应该确保这一点,arr的大小大于等于n

void RandArrayCreate1(int arr[], int n)

{

int temp;

for(int i=0; i<n; ++i)

{

while(true)

{

temp = randInt(1,n);

int j = 0;

while(j<i)

{

if(arr[j] == temp){ break;}

++j;

}

if(j == i)

{

arr[j] = temp;

break;

}

}

}

}

//算法,算法描述如题目.8所示,根据习惯,不对arr[]的大小做任何检验

//调用此函数的人应该确保这一点,arr的大小大于等于n

void RandArrayCreate2(int arr[], int n)

{

//为了正好与数值一一对应,浪费位算了,默认就都为flase

bool *used = new bool[n+1];

memset(used, 0, sizeof(bool) * (n+1));

int temp;

for(int i=0; i<n; ++i)

{

while(true)

{

temp = randInt(1,n);

if(used[temp] == false)

{

arr[i] = temp;

used[temp] = true;

break;

}

else

{

continue;

}

}

}

delete []used;

}

//算法,算法描述如题目.8所示,根据习惯,不对arr[]的大小做任何检验

//调用此函数的人应该确保这一点,arr的大小大于等于n

void RandArrayCreate3(int arr[], int n)

{

for(int i=0; i<n; ++i)

{

arr[i] = i + 1;

}

for(int i=0; i<n; ++i)

{

swap(arr[i], arr[randInt(0, i)] );

}

}

void RandArrayCreate2a(int arr[], int n)

{

//为了正好与数值一一对应,浪费位算了,默认就都为flase

boost::dynamic_bitset<> used(n+1);

int temp;

for(int i=0; i<n; ++i)

{

while(true)

{

temp = randInt(1,n);

if(used[temp] == false)

{

arr[i] = temp;

used.set(temp);

break;

}

else

{

continue;

}

}

}

}

void RandArrayCreate2b(int arr[], int n)

{

//为了正好与数值一一对应,浪费位算了,默认就都为flase

vector<bool> used(n+1);

int temp;

for(int i=0; i<n; ++i)

{

while(true)

{

temp = randInt(1,n);

if(used[temp] == false)

{

arr[i] = temp;

used[temp] = true;

break;

}

else

{

continue;

}

}

}

}

这里对算法的测试用另外一个测试函数来进行:

//因为这里主要是比较不同算法的实现,所以这里不区分算法及其实现,都称为算法

//比较算法的函数,其中算法函数的参数为数组(array)和整数(int)

//简写为AI,为了防止混乱,这里我没有使用函数的重载

//准备以后有新的不同参数的算法时再加入新的比较函数

//比较函数的参数解释如下:

//第一参数:各算法的用vector<>表示的函数指针数组

//第二参数:vector<int>表示的一系列算法函数第二参数,用以做算法增长比较

//主要注意的是,这里的第二参数实际也是算法函数第一参数数组的大小

void CompareAlgorithmAI(const std::vector<pfAI> &pfAIVec,const std::vector<int>& vec)

{

double timeInAll = GetTime(); //这里保存所有比较花费的时间

std::ofstream out("CompareAlogrithmAIResult.txt");//将结果保存在这里

//在文件中输入第一行

out <<"parameter" <<'/t';

for(int i=0; i<pfAIVec.size(); ++i)

{

out <<"Algorithm " <<i+1 <<'/t';

}

out <<std::endl <<std::setprecision(4) <<std::scientific;

double timeTaken; //每个算法一次消耗的时间

//以算法参数的数组个数为循环条件,每个数值让各个算法分别调用

for(int i=0; i<vec.size(); ++i)

{

out <<vec[i] <<'/t';

int *arr = new int[ vec[i] ]; //每次动态生成一个数组

for(int j=0; j<pfAIVec.size(); ++j)

{

timeTaken = GetTime();

pfAIVec[j](arr, vec[i]); //实际调用不同算法

timeTaken = GetTime() - timeTaken;

out <<timeTaken <<'/t';

}

delete []arr; //删除arr,因为只考察算法的效率,所以根本不关心结果

//至于各算法是否正确由调用者保证

out<<std::endl;

}

timeInAll = GetTime() - timeInAll;

out <<"Compared time in all: " <<timeInAll <<std::endl;

}

最后得到的结果用excel打开,实在是更加赏心悦目而且更好的可以保存下来,可以只测试一个,也可以一次测试一组,以后的算法比较中还可以重复的利用,这里利用了vector来传递参数,有利于减少参数的数量。关于GetTime的含义,请参考置顶文章

parameter

RandArrayCreate1

parameter

RandArrayCreate3

250

6.62E-04

100000

1.85E-02

500

4.61E-03

200000

3.78E-02

1000

1.59E-02

400000

5.83E-02

2000

6.70E-02

800000

1.17E-01

Compared time in all: 8.9593e-002

1600000

2.30E-01

3200000

4.61E-01

6400000

9.22E-01

Compared time in all: 1.9196e+000

parameter

RandArrayCreate2

RandArrayCreate2a

RandArrayCreate2b

250

1.30E-04

7.51E-04

1.03E-02

500

2.72E-04

1.64E-03

1.88E-02

1000

6.78E-04

3.49E-03

5.65E-02

2000

1.41E-03

9.19E-03

1.11E-01

4000

2.70E-03

1.47E-02

2.63E-01

8000

5.97E-03

3.84E-02

4.66E-01

16000

1.31E-02

7.39E-02

1.33E+00

32000

3.60E-02

1.91E-01

2.39E+00

Compared time in all: 5.0447e+000

很显然的结果,不多说了,不过书中给出要我运行的第2算法的参数实在是太大了,估计一天都运行不完,这里也可以看到,在动态bool位使用上,直接New最快,用Boost库的动态bit是其次,用标准库的vector<bool>只能用慢的出奇来形容了,当然,其实很多时候都是同样的结论,因为用new毕竟不是那么好管理,但是不需要建构析构,而用了类来管理,自然需要更多的时间资源,但是更好管理并且动态更改起来更加方便。这需要自己去权衡利弊了。

至于最E,最坏情况的分析,前两个在一直随机到重复数字的时候可以到无限大。。。汗!第三个算法是线性的,也无所谓最坏情况。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
The fourth edition of Data Structures and Algorithm Analysis in C++ describes data structures, methods of organizing large amounts of data, and algorithm analysis, the estimation of the running time of algorithms. As computers become faster and faster, the need for programs that can handle large amounts of input becomes more acute. Paradoxically, this requires more careful attention to efficiency, since inefficiencies in programs become most obvious when input sizes are large. By analyzing an algorithm before it is actually coded, students can decide if a particular solution will be feasible. For example, in this text students look at specific problems and see how careful implementations can reduce the time constraint for large amounts of data from centuries to less than a second. Therefore, no algorithm or data structure is presented without an explanation of its running time. In some cases, minute details that affect the running time of the implementation are explored. Once a solution method is determined, a program must still be written. As computers have become more powerful, the problems they must solve have become larger and more complex, requiring development of more intricate programs. The goal of this text is to teach students good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amount of efficiency. This book is suitable for either an advanced data structures course or a first-year graduate course in algorithm analysis. Students should have some knowledge of intermediate programming, including such topics as pointers, recursion, and object-based programming, as well as some background in discrete math.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值