算法设计与分析实验报告Word下载.docx
《算法设计与分析实验报告Word下载.docx》由会员分享,可在线阅读,更多相关《算法设计与分析实验报告Word下载.docx(19页珍藏版)》请在冰豆网上搜索。
四、实验方法与步骤:
合并排序的关键步骤在于合并步骤中的合并两个已排序子序列。
为做排序,引入一个辅助过程merger(A,p,q,r),其中A是个数组,pqr是下标,满足p<
=q<
r。
该过程假设A[p..q]和A[q+1..r]都已排序,并将它们合并成一个已经排好序的子数组代替当前子数组A[p..r]。
函数模板的声明是在关键字template后跟随一个或多个模板在尖括弧内的参数和原型。
与普通函数相对,它通常是在一个转换单元里声明,而在另一个单元中定义,你可以在某个头文件中定义模板。
template<classT>Tmax(Tt1,Tt2)
{return(t1>t2)?
t1:
t2;
}
<classT>定义T作为模板参数,或者是占位符,当实例化max()时,它将替代具体的数据类型。
max是函数名,t1和t2是其参数,返回值的类型为T。
你可以像使用普通的函数那样使用这个max()。
proceduremergesort(varr,r1:
listtype;
s,t:
integer)
{r,r1:
均为链表,存储排序数据;
过程mergesort(r,r1,s,t)完成把链表r中的关键字进行归并排序、并存放到链表r1中,其中s是下界t是上界}<
BR>
{过程merge(r2,s,m,t,r1)把链表r2中排好序的子链r2[s..m]和子链r2[m+1..t]合并到r1中}。
实现时间计量:
#define_CLOCK_T_DEFINED
srand((unsigned)time(0));
#include<
iostream>
ctime>
cstdlib>
#include<
algorithm>
usingnamespacestd;
#ifndef_CLOCK_T_DEFINED
typedeflongclock_t;
#define_CLOCK_T_DEFINED
#endif
//////////////////////////////
classT>
voidMerge(Tc[],Td[],intl,intm,intr)
{
//合并c[1:
m]和c[m+1:
r]到d[1:
r]
inti=l,j=m+1,k=l;
while((i<
=m)&
&
(j<
=r))
{
if(c[i]<
=c[j])
{
d[k++]=c[i++];
}
else
d[k++]=c[j++];
}
if(i>
m)
for(intq=j;
q<
=r;
q++)
d[k++]=c[q];
else
for(intq=i;
=m;
voidMergePass(Tx[],Ty[],ints,intn)
inti=0;
while(i<
=n-2*s)
//合并大小为s的相邻子数组
Merge(x,y,i,i+s-1,i+2*s-1);
i=i+2*s;
//剩下的元素个数少于2s
if(i+s<
n)
Merge(x,y,i,i+s-1,n-1);
for(intj=i;
j<
=n-1;
j++)
y[j]=x[j];
///////////////////////////
voidMergeSort(Ta[],intn)
T*b=newT[n];
ints=1;
while(s<
MergePass(a,b,s,n);
//合并到数组b
s+=s;
MergePass(b,a,s,n);
//合并到数组a
////////////////////////////
voidDisplay(Ta[],intn)
for(inti=0;
i<
n-1;
i++)
cout<
<
a[i]<
"
"
;
cout<
a[n-1]<
endl;
voidmain()
int*a=newint[1000000];
int*b=newint[1000000];
1000000;
srand((unsigned)time(0));
a[i]=rand();
b[i]=a[i];
clock_tstart,finish;
doubleduration;
//开始
start=clock();
MergeSort(a,1000000);
finish=clock();
//结束
duration=(double)(finish-start)/CLOCKS_PER_SEC;
算法时间:
"
<
duration<
s"
std:
sort(b,b+1000000);
duration=(double)(finish-start)/CLOCKS_PER_SEC;
sort函数时间:
&
g[i][j].U);
g[0][0].s=0;
fclose(opf);
CGridRoad:
~CGridRoad()
n;
delete[]g[i];
delete[]g;
voidCGridRoad:
Calculate()
for(intj=0;
for(inti=0;
m;
if(i==0&
j>
0)
{
g[j][i].s=g[j-1][i].s+g[j-1][i].U;
g[j][i].f=DOWN;
}
elseif(j==0&
i>
g[j][i].s=g[j][i-1].s+g[j][i-1].R;
g[j][i].f=LEFT;
elseif(!
(j==0&
i==0))
ints1=g[j][i-1].s+g[j][i-1].R;
ints2=g[j-1][i].s+g[j-1][i].U;
if(s1<
s2)
{
g[j][i].s=s1;
g[j][i].f=LEFT;
}
else
g[j][i].s=s2;
g[j][i].f=DOWN;
OutputShortest(char*sFileName)
inti=n-1,j=m-1;
while(i>
0||j>
Pointp;
=i;
=j;
(p);
if(g[i][j].f==LEFT)
j--;
i--;
PointP;
==0;
(P);
inf=fopen(sFileName,"
w"
);
while(!
())
Pointt=();
();
fprintf(inf,"
(%d,%d)"
,;
fclose(inf);
贪心算法—Huffman树及Huffman编码
一个记录字符及出现频率的文件如下所示:
7
a,45
b,13
c,12
d,16
e,89
f,34
g,20
试编写一个读取此种格式文件类CHuffman,内部机制采用优先队列,用于建立Huffman树及进行Huffman编码输出,其用法可以如下所示:
CHuffmanhm("
=ch1;
(100,'
'
(ch,4);
t[i].f=atoi(ch);
for(inti=0;
cout<
t[i].c<
t[i].f<
endl;
t[i].idx=i;
(t[i]);
while(!
if(())>
=2)
THaffmanNodenn,nr,nl/*,ntemp,ntemp1*/;
nl=();
();
nr=();
=+;
=;
=nNext++;
t[].p=;
t[]=nn;
(nn);
t[2*n-2].p=-1;
break;
CHuffman:
CHuffman(intt1)
this->
n=t1;
nNext=t1;
t=newTHaffmanNode[2*t1-1];
~CHuffman(void)
voidCHuffman:
CreateTree()=;
OutputTree()
{
2*n-1;
权重:
左孩子:
t[i].l<
右孩子:
t[i].r<
父节点:
t[i].p<
在数组的位置:
t[i].idx<
dx==
{
(0);
ntemp=ntemp1;
{
(1);
inti1=();
:
i1;
{
();
CHuffmanchf("
system("
pause"
用回溯方法求解n后问题
问题:
对任意给定的n求解n后问题。
具体要求:
1.封装n后问题为类,编写以下两种算法进行求解:
(1)递归回溯方法;
(2)迭代回溯方法。
(选)
2.对任意给定的n,要求输出其解向量(所有解),并输出其解数;
3.构造n后问题的解数表格(由程序自动生成):
n后数
解数
第一个解
4
2
(2,4,1,3)
5
…
6
回溯法:
确定了解空间的组织结构后,回溯法就从开始结点(根结点)
出发,以深度优先搜索的方式搜索整个解空间。
这个开始结点就成为一个活结点,同时也成为当前的扩展结点。
在当前的扩展结点处,搜索向纵深方向移至一个新结点。
这个新结点就成为一个新的活结点,并成为当前扩展结点。
如果在当前的扩展结点处不能再向纵深方向移动,则当前的扩展结点就成为死结点。
此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。
回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已无活结点时为止。
输入:
皇后的个数N;
输出:
N皇后问题的解的个数以及它的所有可行解。
n皇后问题;
数组a中,a[i]表示第i个皇后放在第i行和第a[i]列,a[0]存放所有可行解的数目;
利用棋盘的对称性,找到一个可行解后,其转置也是一个可行解,所以,只需把第一个皇后从第1列一直扫描到第(n+1)/2列即可,其他解可以根据对称性给出。
问题的解可表示为x[1:
n],表示皇后i放在棋盘的第i行的第x[i]列。
a)x[i]≠x[j],i≠j:
不允许将任何两个皇后放在同一列上;
b)|j-i|≠|x[j]-x[i]|:
不允许两个皇后位于同一条斜线上。
每个解元素生成之后,考察下一个元素能否在本元素的下一列放置,如果place函数的条件均不满足,则放置之,否则则向后放置,如果所有的元素位置都不行,则母元素的列数向后移动一个,再进行循环的考虑,此为回溯思想。
五、实验结果与数据处理:
六、实验心得:
算法附件:
classCQueen
public:
CQueen();
x[k-1]时,判断x[k]能否放置
voidBackTrack(intt);
w[n]
价值
v[1]
v[2]
v[n]
1.将背包问题进行类的封装;
2.能对任意给定的n种物品的重量、价值及背包限重,输出以上表格(或纵向输出);
3.输出背包问题的解;
本题要求采用STL库中的排序算法数据进行排序。
首先计算每种物品单位重量的价值Vi/Wi,然后依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
若将这种物品全部装入背包后,背包内的物品总重量未超出C,则选择单位重量价值次高的物品,并尽可能多的装入背包。
依此策略一直进行下去,直到背包装满为止。
采用贪婪准则:
每次选择p/w最大的物品放入背包。
调用函数库里的排序为sort()函数,括号内部为首地址与未地址。
注意在这之前的计算每种物品单位重量的价值Vi/Wi后,进行排序。
此问题的形式化描述是,给定c>
0,w[i]>
0,v[i]>
0,1≤i≤n,要求找出一个n元0-1向量(x1,x2,…,xn),0≤x[i]≤1,1≤i≤n,使得∑w[i]*x[i]≤c,而且∑v[i]*x[i]达到最大。
用贪心算法解部分背包问题,首先计算每种物品单位重量的价值v[i]/w[i],然后依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包,若将这种物品全部装入背包,背包内的物品总重量没有超过c,则把它全部装入,背包总价值增加v[i],然后选择单位重量价值次高的物品,如果物品重量w[i]超出了背包内剩余的容量c,则选择w[i]的c/w[i]部分放入背包,背包内总价值增加c*v[i]/w[i]。
根据上述分析设定几个基本变量:
intn,c;
分别是物品的个数和背包的容量
floatp[],pack=,avg[];
p为每个物品的价值,pack表示背包内所有物品的价值和,avg表示每个物品的单位重量价值
intw[];
表示物品的重量
>
#definemaxn11
intn=0,c=0,ss;
floattemp=,p[maxn],pack=,avg[maxn];
intw[maxn],list[maxn];
请输入物品的个数n和背包的容量c:
cin>
n>
c;
请输入每件物品的价值和大小:
for(inti=1;
=n;
i++)过本次试验的学习,我熟悉了分治策略、贪心算法、回溯算法等有用的优秀的算法,复习了数据结构课上学到的构造Huffman树的方法。
本次实验的过程中,我学会了文件的读写,这对我来说是一件值得庆贺的事情,我们真应该多学习一点,对以后少走一些弯路是有帮助的!
希望我们都能够好好学习算法,多多思考,能够在解决实际问题上多多优化自己的程序!
2.构建知识框架,不管学习什么,概念是基础,所有的知识框架都是建立在基础概念之上的。
3.对算法的学习,个人认为,对算法的学习是学习数据结构的关键。
在第二遍看课本的过程中,要注重对算法的掌握。
对于一个算法,读一遍可能能读懂,但不可能完全领会其中的思想。
掌握一个算法,并不是说将算法背过,而是掌握算法的思想。
我们需要的是耐心。
每看一遍就会有这一遍的收获。
读懂算法之后,自己再默写算法,写到不会的地方,看看课本想想自己为什么没有想到。
反复练习,直到能顺利写出算法为止。
个人认为,这是行之有效的方法。
这样,不仅可以更加深入的领会算法思想,还会逐渐发现算法的巧妙之处,从而对数据结构及算法产生兴趣。