数据结构与算法专题实验实验报告文档格式.docx
《数据结构与算法专题实验实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构与算法专题实验实验报告文档格式.docx(56页珍藏版)》请在冰豆网上搜索。
#include<
stdio.h>
conio.h>
typedefstruct
{
intlast;
intdata[maxsize];
}seqlist;
//定义顺序表结构体
inttop;
intsum;
}seqstack;
//定义栈结构体
seqstack*init_seqstack()
seqstack*s;
s=newseqstack;
if(!
s)
{
printf("
空间不足"
);
returnnull;
}
else
s->
top=-1;
sum=0;
returns;
}//栈初始化
intempty_seqstack(seqstack*s)
if(s->
top==-1)
return1;
return0;
}//判断空栈
intpush_seqstack(seqlist*l,inti,seqstack*s)//入栈
if(s->
top==maxsize-1)
top++;
data[s->
top]=i;
//顺序表中第i个元素,i入栈
sum=s->
sum+l->
data[i];
//栈中sum加和!
intpop_seqstack(seqlist*l,seqstack*s,int*x)//出栈
if(empty_seqstack(s))
*x=s->
top];
sum-l->
top]];
top--;
seqlist*init_seqlist()
seqlist*l;
intx=1;
l=newseqlist;
l->
last=0;
请依次输入个物品的大小,输入0结束。
\n"
scanf("
%d"
&
x);
while(x!
=0)
data[l->
last]=x;
last++;
returnl;
}//创建数组,储存物品体积
voidknapsk(intn,seqlist*l)
intflag=1;
inti=0;
intt;
s=init_seqstack();
//初始化栈命名为S
while(flag!
while(i<
=l->
last)
push_seqstack(l,i,s);
sum==n)
可行的解是:
"
for(t=0;
t<
=s->
top;
t++)
%d"
l->
data[t]]);
pop_seqstack(l,s,&
i);
i++;
sum>
n)
elsei++;
while(i==l->
last+1)
flag=pop_seqstack(l,s,&
if(flag==0)
执行完毕"
5.运行结果
实验二:
八皇后问题
设在初始状态下在国际象棋的棋盘上没有任何棋子(这里的棋子指皇后棋子)。
然后顺序在第1行,第2行……第8行上布放棋子。
在每一行中共有8个可选择的位置,但在任一时刻棋盘的合法布局都必须满足3个限制条件
(1)任意两个棋子不得放在同一行
(2)任意两个棋子不得放在同一列上(3)任意棋子不得放在同一正斜线和反斜线上。
2.设计要求
编写求解并输出此问题的一个合法布局的程序。
3.解题思路
在第i行布放棋子时,从第1列到第8列逐列考察。
当在第i行第j列布放棋子时,需要考察布放棋子后在行方向、列方向、正斜线和反斜线方向上的布局状态是否合法,若该棋子布放合法,再递归求解在第i+1行布放棋子;
若该棋子布放不合法,移去这个棋子,恢复布放该棋子前的状态,然后再试探在第i行第j+1列布放棋子。
4.算法设计
s1
数据初始化。
s2
从n列开始摆放第n个皇后(因为这样便可以符合每一竖列一个皇后的要求),先测试当前位置(n,m)是否等于0(未被占领)。
如果是,摆放第n个皇后,并宣布占领(记得姚横列竖列斜列一起设置),接着进行递归;
如果不是,测试下一个位置(n,m+1),但是如果当n<
=8,m=8时,发现此时已无法摆放时,便要进行回溯。
从问题的某一种可能出发,搜索从这种情况能出发,继续搜索,这种不断“回溯”的寻找解的方法,称为“回溯法”。
s3
使用数组实现回溯法的思想。
s4
当n>
8时,便打印出结果。
输出函数我使用printf输出,运行形式为:
第m种方法为:
00000*00
5.程序源码
staticboard[8][8];
intknock(inti,intj)//放置棋子
inttemp_i,temp_j,k;
temp_i=i;
temp_j=j;
for(i=i-1;
i>
=0;
i--)
if(board[i][j]==1)
for(i=temp_i-1,k=temp_j+1,j=temp_j-1;
i--,j--,k++)
if(j>
=0&
&
board[i][j]==1)
if(k<
8&
board[i][k]==1)
return0;
}
voidchess(inti)//设置棋盘
intj;
for(i=i;
i<
8;
i++)
for(j=0;
j<
j++)
board[i][j]=0;
voiddisplay(void)//输出
inti,j;
staticintn=1;
\n第%d种\n"
n++);
for(i=0;
*"
0"
voidfun(inti,intj)
if(i<
8)
for(j=j;
chess(i);
if(knock(i,j)==1)
continue;
board[i][j]=1;
fun(i+1,0);
else
display();
voidmain()
fun(0,0);
6.运行结果(部分)
实验三:
哈夫曼压缩/解压缩算法(编译码器)
利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,要求在发送端通过一个编码系统对传输数据预先编码(压缩);
在接收端将传来的数据进行译码(解压缩复原)。
试为这样的通信站编写一个哈夫曼编译码系统---哈夫曼压缩/解压缩算法。
1)通信内容可以是任意的多媒体文件;
2)自己设定字符大小,统计该文件中不同字符的种类(字符集、个数)、出现频率(在该文件中);
3)构建相应的哈夫曼树,并给出个字符的哈夫曼编码;
4)对源文件进行哈夫曼压缩编码形成新的压缩后文件(包括哈夫曼树);
5)编写解压缩文件对压缩后文件进行解码还原成源文件。
不同源文件形成的压缩文件中应该包含相应的哈夫曼树结构,以便解压缩系统直接译码还原之。
参考哈夫曼树一节内容,但要求编写的软件能完整的对任意文件完成压缩/解压缩。
(1)压缩文件
压缩文件时要先对源文件进行统计,统计字符的种类及出现的次数(即权值)。
统计完成之后,建立哈弗曼树:
每次选取权值最小且无parent的结点作为左右孩子,建成一棵二叉树,且设置新的二叉树的根结点的权值为其左右孩子的权值之和。
直至建成含有2*n-1个结点的哈弗曼树。
编码完成之后,开始对源文件进行压缩。
从源文件读一个字符,从叶子结点中找出和此字符相同的字符结点,将其编码写入一个临时字符组codes;
当codes的长度大于等于8时,将其前8位转换成字符写入目标文件中;
重复1和2此过程,直至读完源文件中的所有字符;
若codes最后还有剩余的不足8位的01代码,则将其低位补0至8位,再写入目标文件。
(2)解压文件
从被压缩的文件中读出FileLength、n的值,以及每个叶子结点的信息:
字符、字符对应的编码。
从被压缩的文件编码区读出一个字符,将其值转化成二进制形式(不足8位的高位要补0),存入codes中,直至codes的长度不小于所有叶子结点的编码的长度;
用for循环查找出第一个和codes的01字符串匹配的叶子结点编码,将该叶子结点的字符写入目标文件,并将codes的字符串前移,前移位数=该叶子结点编码的长度。
重复1和2过程,直至写入的字符数与源文件的长度FileLength相同。
#include<
string.h>
stdlib.h>
time.h>
structnode{
longweight;
//权值
unsignedcharch;
//字符
intparent,lchild,rchild;
charcode[256];
//编码的位数最多为256位
intCodeLength;
//编码长度
}hfmnode[512];
voidcompress();
voiduncompress();
//主函数
intchoice;
请选择1~3:
1.压缩文件\n"
2.解压文件\n"
3.退出\n"
scanf("
choice);
if(choice==1)compress();
elseif(choice==2)uncompress();
elseif(choice==3)return;
elseprintf("
输入错误!
//压缩函数
voidcompress()
charinfile[20],outfile[20];
FILE*ifp,*ofp;
unsignedcharc;
//
longFileLength,filelength=0;
intn,m;
//叶子数和结点数
ints1,s2;
//权值最小的两个结点的标号
charcodes[256];
longsumlength=0;
floatrate,speed;
intcount=0;
clock_tstart1,start2,finish1,finish2;
doubleduration1,duration2;
voidencode(structnode*nodep,intn);
//编码函数
intselect(structnode*nodep,intpose);
//用于建哈弗曼树中选择权值最小的结点的函数
请输入要压缩的文件名:
%s"
infile);
ifp=fopen(infile,"
rb"
if(ifp==NULL)
printf("
文件名输入错误,文件不存在!
return;
请输入目标文件名:
outfile);
ofp=fopen(outfile,"
wb"
if(ofp==NULL)
}
start1=clock();
//开始计时1
//统计文件中字符的种类以及各类字符的个数
//先用字符的ASCII码值代替结点下标
FileLength=0;
while(!
feof(ifp))
{
fread(&
c,1,1,ifp);
hfmnode[c].weight++;
FileLength++;
FileLength--;
//文件中最后一个字符的个数会多统计一次,所以要减一
hfmnode[c].weight--;
//再将ASCII转换为字符存入到结点的ch成员里,同时给双亲、孩子赋初值-1
n=0;
256;
if(hfmnode[i].weight!
{
hfmnode[i].ch=(unsignedchar)i;
n++;
//叶子数
hfmnode[i].lchild=hfmnode[i].rchild=hfmnode[i].parent=-1;
}
m=2*n-1;
//哈弗曼树结点总数
j=0;
i++)//去掉权值为0的结点
if(hfmnode[i].weight!
hfmnode[j]=hfmnode[i];
j++;
for(i=n;
m;
i++)//初始化根结点
hfmnode[i].lchild=hfmnode[i].rchild=-1;
hfmnode[i].parent=-1;
//建立哈弗曼树
for(i=n;
s1=select(hfmnode,i-1);
hfmnode[i].lchild=s1;
hfmnode[s1].parent=i;
s2=select(hfmnode,i-1);
hfmnode[i].rchild=s2;
hfmnode[s2].parent=i;
hfmnode[i].weight=hfmnode[s1].weight+hfmnode[s2].weight;
//编码
encode(hfmnode,n);
finish1=clock();
duration1=(double)(finish1-start1)/CLOCKS_PER_SEC;
/*printf("
哈弗曼树编码用时为:
%fseconds\n"
duration1);
*/
编码完成,是否查看编码信息:
yorn?
c=getch();
if(c=='
y'
)
{printf("
叶子数为%d,结点数为%d\n"
n,m);
for(i=0;
n;
printf("
%d号叶子结点的权值为:
%ld,双亲为:
%d,左右孩子:
%d,编码为:
%s\n"
i,hfmnode[i].weight,hfmnode[i].parent,hfmnode[i].lchild,hfmnode[i].code);
}
start2=clock();
//开始计时2
fseek(ifp,0,SEEK_SET);
//将ifp指针移到文件开头位置
fwrite(&
FileLength,4,1,ofp);
//将FileLength写入目标文件的前4个字节的位置
fseek(ofp,8,SEEK_SET);
//再将目标文件指针ofp移到距文件开头8个字节位置
codes[0]=0;
//将编码信息写入目标文件
feof(ifp))
filelength++;
for(i=0;
if(c==hfmnode[i].ch)break;
//ch必须也为unsigned型
strcat(codes,hfmnode[i].code);
while(strlen(codes)>
=8)
i++)//将codes的前8位01代码表示的字符存入c
{
if(codes[i]=='
1'
c=(c<
<
1)|1;
elsec=c<
1;
}
c,1,1,ofp);
//将新的字符写入目标文件
sumlength++;
strcpy(codes,codes+8);
//更新codes的值
if(filelength==FileLength)break;
//再将剩余的不足8位的01代码补全8位,继续写入
if(strlen(codes)>
0)
strcat(codes,"
00000000"
)
c=(c<
sumlength++;
sumlength+=8;
printf("
编码区总长为:
%ld个字节\n"
sumlength-8);
//将sumlength和n的值写入目标文件,为的是方便解压
fseek(ofp,4,SEEK_SET);
sumlength,4,1,ofp);
//把sumlength写进目标文件的第5-8个字节里
fseek(ofp,sumlength,SEEK_SET);
n,4,1,ofp);
//把叶子数n写进编码段后面的4个字节的位置
//为方便解压,把编码信息存入n后面的位置
//存储方式为:
n*(字符值(1个字节)+该字符的01编码的位数(1个字节)+编码(字节数不确定,用count来计算总值))
(hfmnode[i].ch),1,1,ofp);
c=hfmnode[i].CodeLength;
//编码最长为256位,因此只需用一个字节存储
//写入字符的编码
if(hfmnode[i].CodeLength%8!
=0)
for(j=hfmnode[i].CodeLength%8;
j++)//把编码不足8位的在低位补0,赋值给C,再把C写入
strcat(hfmnode[i].code,"
0"
while(hfmnode[i].code[0]!
=0)//开始存入编码,每8位二进制数存入一个字节
c=0;
if(hfmnode[i].code[j]=='
strcpy(hfmnode[i].code,hfmnode[i].code+8);
//编码前移8位,继续存入编码
count++;
//编码占的字节数的总值
finish2=clock();
duration2=(double)(finish2-start2)/CLOCKS_PER_SEC;
写入目标文件用时为:
duration2);
printf("
压缩用时为:
duration1+duration2);
speed=(float)FileLength/(duration1+duration2)/1000;
\n压缩速率为:
%5.2fKB/S\n"
speed);
源文件长度为:
FileLength);
sumlength=sumlength+4+n*2+count;