算法设计作业.docx

上传人:b****7 文档编号:10182061 上传时间:2023-02-09 格式:DOCX 页数:52 大小:253.42KB
下载 相关 举报
算法设计作业.docx_第1页
第1页 / 共52页
算法设计作业.docx_第2页
第2页 / 共52页
算法设计作业.docx_第3页
第3页 / 共52页
算法设计作业.docx_第4页
第4页 / 共52页
算法设计作业.docx_第5页
第5页 / 共52页
点击查看更多>>
下载资源
资源描述

算法设计作业.docx

《算法设计作业.docx》由会员分享,可在线阅读,更多相关《算法设计作业.docx(52页珍藏版)》请在冰豆网上搜索。

算法设计作业.docx

算法设计作业

LCS算法

LCS是LongestCommonSubsequence的缩写,即最长公共子序列。

一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。

复杂度:

对于一般的LCS问题,都属于NP问题。

当数列的量为一定的时,都可以采用动态规划去解决。

解法:

动态规划的一个计算最长公共子序列的方法如下,以两个序列X、Y为例子:

  设有二维数组f[i][j]表示X的i位和Y的j位之前的最长公共子序列的长度,则有:

  f[1][1]=same(1,1)

  f[i][j]=max{f[i-1][j-1]+same(i,j),f[i-1][j],f[i][j-1]}

  其中,same(a,b)当X的第a位与Y的第b位完全相同时为“1”,否则为“0”。

  此时,f[i][j]中最大的数便是X和Y的最长公共子序列的长度,依据该数组回溯,便可找出最长公共子序列。

该算法的空间、时间复杂度均为O(n^2),经过优化后,空间复杂度可为O(n),时间复杂度为O(nlogn)。

代码的实现:

#include

usingnamespacestd;

#defineN100

intc[N][N]={0};

intC[N][N]={0};

intK=0;

intJ=0,I=0;

intlcs(char*x,char*y,intm,intn)

{

if(m<0||n<0)

{

return0;

}

if(x[m]==y[n])

{

if(I==0)

{

if(J>=n)

{

return0;

}

}

if(J==0)

{

if(I>=n){return0;}

}

returnK+1;

}

else

{

return0;

}

}

intmain(intargc,char**args)

{inti,j,max;

char*x="abcdefg";

char*y="badcfehgj";

//正序

cout<<"";

for(j=0;j

{

cout<<""<

}

cout<

for(i=0;i

{

for(j=0;j

{

c[i][j]=lcs(x,y,i,j);

if(K

{J=j;

K=c[i][j];

j=strlen(y);

}

}

}

for(i=0;i

{

cout<

for(j=0;j

{

cout<

}

cout<

}

max=K;

//反序

K=0;

J=0;

cout<<"";

for(i=0;i

{

cout<<""<

}

cout<

for(j=0;j

{

for(i=0;i

{

C[j][i]=lcs(y,x,j,i);

if(K

{I=i;

K=C[j][i];

i=strlen(x);

}

}

}

for(j=0;j

{

cout<

for(i=0;i

{

cout<

}

cout<

}

if(max>K)

{

cout<<"最大子串的长度:

"<

cout<<"最大子串为:

";

for(i=0;i

for(j=0;j

{

if(c[i][j]!

=0)

{

cout<

"<

}

}

cout<

}

if(max

{

cout<<"最大子串的长度:

"<

cout<<"最大子串为:

";

for(i=0;i

for(j=0;j

{

if(C[i][j]!

=0)

{

cout<

"<

}

}

cout<

}

if(max==K)

{

cout<<"最大子串的长度:

"<

cout<<"最大子串1为:

";

for(i=0;i

for(j=0;j

{

if(c[i][j]!

=0)

{

cout<

"<

}

}

cout<

cout<<"最大子串2为:

";

for(i=0;i

for(j=0;j

{

if(C[i][j]!

=0)

{

cout<

"<

}

}

cout<

}

}

 

结果:

 

N-皇后问题

1.问题描述

在n×n格的棋盘上放置彼此不受攻击的n个皇后。

际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n皇后问题等价于在n×n格的棋盘上放置n个皇后。

任何2个皇后不放在同一行或同一列或同一斜线上。

2.算法设计

设计一个解n皇后问题的对队列式分支限界法,计算在n×n个方格上放置彼此不收攻击的n个皇后的一个放置方案。

3.方法思想

回溯法是一个既带有系统性又带有跳跃性的搜索算法。

它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。

算法搜索至解空间树的任何一结点时,先判断该结点是否包含问题的解。

如果肯定不包含,则跳过对以该结点为根的子树的搜索,逐层向其祖先结点回溯;否则进入该子树,继续按深度优先策略搜索。

 

代码实现:

#include

#include

boolPlace(intk,int*x){

inti;

for(i=0;i

if((abs(k-i)==abs(x[k]-x[i]))||x[i]==x[k])returnfalse;

returntrue;}

voidBacktrack(intn,int*x,int&sum){

intk=0,i;x[0]=0;

while(k>=0){

x[k]+=1;

while((x[k]<=n)&&!

(Place(k,x)))

x[k]+=1;

if(x[k]<=n){

if(k==n-1){

sum++;

printf("第̨²%d种?

情¨¦况?

:

:

",sum);

for(i=0;i

printf("%d",x[i]);

printf("\n\n");}

else{k++;x[k]=0;}}

else

k--;

}

}

intmain(void){

int*x;intn,i,sum=0;

printf("请?

输º?

入¨?

皇¨º后¨®的Ì?

个?

数ºy?

\n");

scanf("%d",&n);

x=(int*)malloc(n*sizeof(int));

if(x==NULL){

printf("\n");

exit(-1);}

for(i=0;i

Backtrack(n,x,sum);

printf("总Á¨¹共2有®D%d种?

情¨¦况?

\n\n",sum);

free(x);

system("pause");

return0;

}

 

结果:

快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。

由C.A.R.Hoare在1962年提出。

它的基本思想是:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

假设要排序的数组是A[1]……A[N],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。

一躺快速排序的算法是:

1)、设置两个变量I、J,排序开始的时候I:

=1,J:

=N;

2)以第一个数组元素作为关键数据,赋值给X,即X:

=A[1];

3)、从J开始向前搜索,即由后开始向前搜索(J:

=J-1),找到第一个小于X的值,两者交换;

4)、从I开始向后搜索,即由前开始向后搜索(I:

=I+1),找到第一个大于X的值,两者交换;

5)、重复第3、4步,直到I=J;

例如:

待排序的数组A的值分别是:

(初始关键数据X:

=49)

A[1]     A[2]     A[3]     A[4]     A[5]      A[6]     A[7]:

  

49        38       65       97       76       13        27

进行第一次交换后:

   27        38       65       97       76       13        49

(按照算法的第三步从后面开始找

进行第二次交换后:

   27        38       49       97       76       13        65

(按照算法的第四步从前面开始找>X的值,65>49,两者交换,此时I:

=3)

进行第三次交换后:

   27        38       13       97       76       49        65

(按照算法的第五步将又一次执行算法的第三步从后开始找

进行第四次交换后:

   27        38       13       49       76       97        65

(按照算法的第四步从前面开始找大于X的值,97>49,两者交换,此时J:

=4)

此时再执行第三不的时候就发现I=J,从而结束一躺快速排序,那么经过一躺快速排序之后的结果是:

27        38       13       49       76       97        65,即所以大于49的数全部在49的后面,所以小于49的数全部在49的前面。

快速排序就是递归调用此过程——在以49为中点分割这个数据序列,分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图6所示:

初始状态                        {49     38     65     97     76     13     27}    

进行一次快速排序之后划分为      {27     38     13}     49   {76     97     65}

分别对前后两部分进行快速排序       27     

结束         结束    {49    65}    76    

49           结束

结束

图6    快速排序全过程

1)、设有N(假设N=10)个数,存放在S数组中;

2)、在S[1。

N]中任取一个元素作为比较基准,例如取T=S[1],起目的就是在定出T应在排序结果中的位置K,这个K的位置在:

S[1。

K-1]<=S[K]<=S[K+1..N],即在S[K]以前的数都小于S[K],在S[K]以后的数都大于S[K];

3)、利用分治思想(即大化小的策略)可进一步对S[1。

K-1]和S[K+1。

N]两组数据再进行快速排序直到分组对象只有一个数据为止。

如具体数据如下,那么第一躺快速排序的过程是:

数组下标:

1      2      3      4      5      6      7      8      9      10

45     36     18     53     72     30     48     93     15      36

I                                                                   J

(1)      36     36     18     53     72     30     48     93     15      45

(2)      36     36     18     45     72     30     48     93     15      53

(3)      36     36     18     15     72     30     48     93     45      53

(4)      36     36     18     15     45     30     48     93     72      53

(5)      36     36     18     15     30     45     48     93     72      53

通过一躺排序将45放到应该放的位置K,这里K=6,那么再对S[1。

5]和S[6。

10]分别进行快速排序。

实现代码:

#include

#defineLENGTH100/*数组最大存放量*/

voidqsort(longintshuju[],shortintshangbiao,shortintxiabiao);

voidmain()

{

shortinti,n;

longintshuju[LENGTH];

printf("Howmanynumbers?

\n");/*要输入多少个数*/

scanf("%d",&n);

getchar();/*干掉个多事的回车符*/

printf("inputthenumbers:

\n");

for(i=0;i

qsort(shuju,0,n-1);/*调用递归排序*/

printf("result:

\n");

for(i=0;i

putchar('\n');

getchar();

getchar();/*暂停看结果*/

}

voidqsort(longintshuju[],shortintshangbiao,shortintxiabiao)

{

shortinti=shangbiao,j=xiabiao;/*i和j用来确定还需要判断排序的范围上下标*/

shortintshu=i;/*记录基准点*/

longintzhongjie;

if(shangbiao

{

while(i

{

for(;j>shu;j--)/*对基准数右边扫描*/

{

if(shuju[j]

{

zhongjie=shuju[j];

shuju[j]=shuju[shu];/*进行交换*/

shuju[shu]=zhongjie;

shu=j;/*确定交换后的基准数*/

break;/*跳出循环*/

}

}

i++;/*往右推*/

for(;i

{

if(shuju[i]>shuju[shu])/*如果左边有比基准数大的*/

{

zhongjie=shuju[i];

shuju[i]=shuju[shu];/*交换*/

shuju[shu]=zhongjie;

shu=i;/*交换后的基准点*/

break;

}

}

j--;/*往左推*/

}/*执行完后,比基准点小的都在左边,比基准点大的都在右边了*/

qsort(shuju,shangbiao,shu-1);/*对左边比基准点小的再次进行排序(递归调用)*/

qsort(shuju,shu+1,xiabiao);/*对右边比基准点大的再次执行上面的排序方法(递归调用)*/

}/*直到只剩下要排序一个数为止,此时整个数组已经排序好了*/

}

结果为:

 

堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

  

(1)用大根堆排序的基本思想

  ①先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区

  ②再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key

  ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。

然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。

  ……

  直到无序区只有一个元素为止。

  

(2)大根堆排序算法的基本操作:

  ①初始化操作:

将R[1..n]构造为初始堆;

  ②每一趟排序的基本操作:

将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。

  注意:

  ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。

  ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。

堆排序和直接选择排序相反:

在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止

特点

堆排序(HeapSort)是一树形选择排序。

堆排序的特点是:

在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录。

算法分析

  堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。

  堆排序的最坏时间复杂度为O(nlogn)。

堆序的平均性能较接近于最坏性能。

  由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

  堆排序是就地排序,辅助空间为O

(1),

  它是不稳定的排序方法。

实现代码:

#include

usingnamespacestd;

voidheapadjust(int*&hh,ints,intm);//建立大顶堆函数

voidheapsort(int*h,intq);//堆排序函数

inth[100];//定义待排序数据的存储结构

voidmain()

{

inti=1;//

intj=0;//辅助变量

intq=0;//记录当前数据个数

cout<<"输入待排序数据(-1退出):

"<

cout<<"第"<

";//

cin>>j;//

while(j!

=-1)//输入数据

{

h[i]=j;

q++;

i++;

cout<<"第"<

";

cin>>j;

}

heapsort(h,q);//调用堆排序函数

cout<<"由小到大分别为:

";//对排序后的数据循环输出

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

{

cout<

}

cout<

}

voidheapadjust(int*&hh,ints,intm)//建立大顶堆

{

intrc=0;//记录当前调整位置的数据大小

intj=0;//控制变量

for(j=2*s;j<=m;s=j,j*=2)//j初始化为调整位置的左孩子

{

rc=hh[s];

if(j

{

++j;//改变j值

}

if(rc>=hh[j])//无需调整的情况

{

break;

}

hh[s]=hh[j];//

hh[j]=rc;//换位调整数据和它的某个孩子

}

}

voidheapsort(int*h,intq)

{

inti=0;//

inta=0;//辅助变量

for(i=q/2;i>0;--i)//从q/2处开始调整

{

heapadjust(h,i,q);//调用建大堆函数

}

for

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

当前位置:首页 > 表格模板 > 合同协议

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

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