数据结构课程实验报告Word文档格式.docx
- 文档编号:16597206
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:33
- 大小:238.46KB
数据结构课程实验报告Word文档格式.docx
《数据结构课程实验报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构课程实验报告Word文档格式.docx(33页珍藏版)》请在冰豆网上搜索。
2)以大O的形式分析这些操作的时间复杂度。
4、重新编写一个优先队列的数据结构,该数据结构采用的物理实现是BST。
【实验步骤】
第一题
【需求分析】
根据数学狭义函数的定义,一个函数的函数值随参数的确定而确定。
推广到泛函(参数不一定是数的称泛函)也一样,所以如果两个参数的函数值不相等,则两个参数绝对不相等。
但是反之不成立。
因为存在多重解(同义词)。
根据这个性质,我们定义一个
Hash函数从“字符串域”到“非负整数域”,对应法则是
H(x)=x各个字符的ASCII编码算术和。
比如H(“AB”)=65+66=131;
这种方法的好处是很容易从前一个Hash值计算出nextHash值,且计算速度很快。
坏处是重码比较多。
先对模式串求Hash函数值,保存在hash_pattern中,这是个定值。
然后对目标传的各个子串(长度同模式串)求Hash函数值。
从Hash的定义上来看,目标子串后移一位,很容易就能从前一个Hash函数值中计算出当前字串的Hash值。
然后比较两个的hash值,如果不等,那么肯定不可能匹配。
如果相等,进一步检查。
检查方法是逐字比较,BruteForce穷举法。
我们让目标串当前字符指针和模式串指针如果指的值相等,那么一直向后移。
如果最后发现模式串指针到达“尽头”,那么说明逐字相等。
【源代码】
/*--------------------------------------------------------------------------
StringMatching.CPP--whethertargetstringandpatternstringmatch
Versionalpha
(c)XianfuPan,2010
---------------------------------------------------------------------------*/
#include"
stdio.h"
#include<
iostream>
string.h"
#defineTest
constintTAR=30;
constintPAT=10;
intHash(constchar*aKeyStr,constintnLen)//getHashvalue
{
char*p=(char*)aKeyStr;
inti=0;
inth=0;
while(i++<
nLen)
{
h=(h+*p++);
//addeveryASCIIcode
returnh;
}
intsearch(constchar*TargetStr,constchar*PatternStr)//search
char*p1=(char*)(TargetStr);
constintlen=strlen(PatternStr);
inthash_target=Hash(p1,len);
constinthash_pattern=Hash(PatternStr,len);
while('
\0'
!
=*p1)
if(hash_target==hash_pattern)
{
char*temp=p1;
char*p2=(char*)PatternStr;
while(*temp!
='
&
&
*p2!
*temp++==*p2++)
//onlyifeverycharacterisequalcan*preachtheend(*p2==0);
if(*(p2)=='
)
returnp1-TargetStr;
//p1-TargetStristhepositionfirstmatch
}
//ifHashvauleisnotequal,getnextsubString'
sHashvalue;
hash_target=(hash_target-*p1)+*(p1+len);
p1++;
return-1;
//ifcan'
tmatch,thenreturn-1
intmain(intarg,char*argv[])
std:
:
cout<
<
search("
Computerismybestfriend"
"
est"
)<
endl;
Iloveprogrammingverymuch"
em"
search("
DataStructureisofcharming"
is"
return0;
【运行结果】
经验证,16,-1,14都是预期的值,该算法是有效的。
【复杂度分析】
假设目标串的长度是m,模式串的是n,那么计算两个串Hash值耗费的时间是
n+n=2n,而从前一个字串hash值计算后一个基本上不耗时,耗费时间为1(常数)。
通过比较,如果任意和模式串等长度的子串hash值都不等于模式串Hash值,那么就是匹配失败。
AMLunsucc=m–n+1;
如果成功的话,平均比较(m–n+1)/2次。
而每次计算hash值的时间又是1,平均一共计算了(m–n+1)/2次Hash值,若是两个Hash值相等,那么继续逐字比较,消耗的时间也不过是n/2所以时间复杂度应该是O(mn),但是值得注意的是;
两个Hash值相等的概率比较小,虽然复杂度仍然是O(mn)但是运算次数肯定较原版bruteforce少。
【小结】
关键是如何从前一个Hash值很快得到下一个Hash值。
本题加深了同义词的概念的理解。
Hash值相等,并不一定关键码相同。
第二题
判断两棵二叉树是否相似,首先得得到两棵二叉树,笔者采用输入字符串的方式建立二叉树。
假定”RefValue”=‘#’表示一个结点无孩子,应为二叉树不是线性结构,采用前序遍历顺序穿插RefValue的字符串(线性结构)来构建一个非线性的二叉树
比如:
字符串“AB#D##C##”就构建出如下的树
关于相似性的定义如下:
由定义:
很容易得出关键代码为
Similar(a,b)
If(a空&
b空)Return相似//递归终止条件
If(a不空&
b不空&
similar(a的左子树,b的左子树)&
similar(a的右子树,b的右子树)
Return相似
Else
Return不相似
完全是运用定义。
现在提供版本二,也是定义,先假定相似,给flag赋予true;
然后把flag的引用传递到各个递归层,(级数越高引用越多,但是flag的值始终是引用传递,任意一个递归层改变了参数值就会影响到Flag的真假)运用相似的定义去尝试否定flag。
一旦有一个某级子树不相似,就给flag赋假。
如果没有找到一个子树不是对应相似的,那么flag保持默认值为真。
SIMILARBinaryTree.CPP--judgementtotwobinarytreeswhethersimilar
alpha
//#defineTest
template<
typenameT>
classBinTreeNode
public:
BinTreeNode(Tx,BinTreeNode<
T>
*left=NULL,BinTreeNode<
*right=NULL)
:
m_Data(x),m_LeftChild(left),m_RightChild(right)
{}
~BinTreeNode()
{}
//becauseSimilarfunctionisaglobalfunctionratherthanamemberfunction,sopublic:
Tm_Data;
BinTreeNode<
*m_LeftChild,*m_RightChild;
};
classBinTree
BinTree()
m_Root=NULL;
BinTree(constchar*strTree)//constructortobuildatree
char*p=(char*)strTree;
CreateTree(p,m_Root);
//PreOrdertocreateatree
}
//'
'
isveryimportant.Itplayarolepassingdownaddress
voidCreateTree(char*&
p,BinTreeNode<
*&
subTree)
{
if('
=*p)
{//define'
#'
amarktodeclarethatthisnodehasnoleft/rightchildnode
if('
=*p)
{//allocatememoryandinitialthenodewithdata*p,andNULL,NULL
subTree=newBinTreeNode<
(*p);
p++;
//CreateSubTreeforbothchildrenofthisTree
CreateTree(p,subTree->
m_LeftChild);
m_RightChild);
}
else
{
subTree=NULL;
//if'
==*pthen,nochild,soassignNULL
~BinTree()//definedestructorincaseofmemoryleak
Destroy(m_Root);
voidPreOrder()
std:
"
PreOrderTraverseareasfollows"
<
PreView(this->
m_Root);
voidPreView(BinTreeNode<
*subTree)
if(NULL!
=subTree)
std:
subTree->
m_Data<
PreView(subTree->
voidDestroy(BinTreeNode<
*aTree)
if(NULL!
=aTree)
Destroy(aTree->
#ifdefTest
deleting"
std:
#endif
deleteaTree;
//ONLYpostOrderDeletingisavailabletoDestroy;
*m_Root;
//Version1,Definationbased;
template<
boolSimilar(BinTreeNode<
*aTree,BinTreeNode<
*bTree)
{//iftheyarebothempty,accordingtodefination,similar
if(NULL==aTree&
NULL==bTree)
returntrue;
if(NULL!
=aTree&
NULL!
=bTree
//ifbotharenot,andtheirchildrenaresimilarrespectly
&
Similar(aTree->
m_LeftChild,bTree->
m_LeftChild)
m_RightChild,bTree->
m_RightChild))//
else//else,notsimilar;
returnfalse;
//Version2,Greedalgorithm
voidSimilar(BinTreeNode<
*bTree,bool&
flag)
if((NULL==aTree)&
(NULL==bTree))//onlyiftheyareempty
return;
if((NULL!
=aTree)==(NULL!
=bTree))
{//onlyiftheyareemptyornotsimultaneously,theyarelikelytobesimilar
Similar(aTree->
m_LeftChild,flag);
m_RightChild,flag);
else//oneisemptybutonenot,whichdrawaconclusionthatnotsimilar
flag=false;
intmain(intargc,char*argv[])
charbuffer[50];
cout<
inputfirsttreelike\"
ABC##DE#G##F###\"
"
cin>
>
buffer;
BinTree<
char>
fTree(buffer);
inputsecondtreelike\"
sTree(buffer);
fTree.PreOrder();
sTree.PreOrder();
------------------------------------------"
boolflag=Similar<
(fTree.m_Root,sTree.m_Root);
//Similarfunctionversion1
if(flag)
Theyaresimilar"
else
Theyarenotsimilar"
flag=true;
//assumptheyaresimilar,thenmakeeveryattemptodenyit,
//followingfunctiondoesthejob
Similar<
(sTree.m_Root,fTree.m_Root,flag);
//Similarfunctionversion2
flag<
相似的情况不相似的情况
递归算法,在similar(n-1)返回前,similar(n)被挂起。
因为是遍历(变相遍历)二叉树,所以时间复杂度是:
O(n)n为二叉树的结点数。
但是注意到&
运算的短路性质,故真正用的时间是O(logn);
理解递归思想很重要,递归的思想来自于事物的定义。
把大的问题分解成小的问题,但是小问题和大问题“相似”,那么就可以考虑用递归。
每一层递归只要考虑当前层就行,另外递归需要一个终止条件,那就是找到n=1时,强行定义f
(1)=某个值。
第三题
依据题意,编写一个基于堆的栈,就是说:
对外部来说,栈还是栈结构,即FILO或者LIFO先进后出或后进先出。
但是,这个栈是基于堆的,对于内部来说,数据是按照堆序排列的。
所以说如果从栈的操作PushPop转化到堆的操作Insert,Remove就是一个最大的问题。
由于栈表示的是一种时间上的先后,基于数组或者链表的栈时间上的先后性其实就反映在空间上的先后性。
因为后(后表示时间概念)进来的元素总是比先进来的元素存放的地址(地址表示空间概念)靠后。
两者的关系是一次线性对应。
而堆序只是一种数值大小的先后,空间的先后无法反映到进栈时间的先后,当栈Push的时候,只要按堆序存入,调整位置就行。
当然没有问题,而当Pop的时候,存在堆中的数据因为缺乏一种空间上的顺序性,无法确定是哪个元素出栈。
解决这个问题的方法就是给进入的元素增加时间标签这个信息,使得进了堆的元素在Pop的时候能够知道是哪个该出堆了。
时间标签的值就是栈大小的值,或者说是栈顶元素的位置。
HeapBasedStack.CPP--aStackBasedOnHeap(minHeap)
constintMAX=40;
structNode
intm_iTimeTag;
//whenfunctionargumentpassdown,ituseoperator=indirectly;
//you'
dbetteroverloadoperator=,thoughhereisnotnessesary
Node<
operator=(Node<
other)
m_Data=other.m_Data;
m_iTimeTag=other.m_iTimeTa
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程 实验 报告