离散数学课程设计论文.docx
《离散数学课程设计论文.docx》由会员分享,可在线阅读,更多相关《离散数学课程设计论文.docx(26页珍藏版)》请在冰豆网上搜索。
离散数学课程设计论文
09届课程(设计)论文
题目
基于二元树的随机序列独立性分析算法与实现
专业班级
信息与计算科学
(2)班
学号
学生姓名
指导教师
指导教师职称
副教授
学院名称
理学院
完成日期:
2011年7月1日
目录
目录I
摘要II
前言III
第1章课题背景1
1.1问题背景1
1.2基础知识1
1.3意义1
1.4文献综述2
第2章基于二元树的随机变量序列相依阶数估计3
2.1算法概述3
2.2数据结构设计
第3章功能函数实现5
3.1二叉树结点插入5
3.2二叉树的建立5
3.3二叉树层次遍历6
3.4程序与所实现的调度方案7
3.5程序的优缺点及改进13
第4章总结14
致谢15
参考文献16
附录17
摘要
随机变量序列中的符号不是独立的,通过程序的结果,统计出二元随机序列每一维序列频数,最后,我们要根据所得出的频数来分析与统计二元树随机变量序列相依阶数,找出随机序列中的最大独立单元。
在该程序中,随机变量序列为随机的二进制串。
关键词:
二元随机序列,频数,相依阶数,最大独立单元,二进制串
前言
本文解决了通过二叉树的链表方式存储数据并计算二叉树每个结点的频数。
全文共四章。
第1章介绍了问题背景以及相关的基础知识。
在本章中,还给出了具体的实例分析和与之相关的定理。
第2章主要介绍了解决课题的算法概述以及数据结构设计。
第3章主要介绍了功能函数的实现,其中包括二叉树结点插入、二叉树的建立以及二叉树层次遍历。
第4章是本次课程设计的总结。
全文的最后是致谢、参考文献和对程序优化处理的源代码。
****
2011-7-1于武汉工程大学理学院
第1章课题背景
1.1问题背景
随机变量序列的独立性与相依性是概率论中很重要的概念。
许多随机变量序列中的符号的出现都与其前面若干个符号有依赖关系,在研究分析时限制随机序列的记忆长度,当记忆长度固定时,这样的记忆信源为马尔可夫信源。
而实际上,有很多随机序列的记忆长度不是固定的,这样随机序列相依阶数是变化的。
基于二元树随机变量序列相依阶数估计是通过分析树结点的空间分布,可以判定出该随机变量序列是独立还是相依的。
若随机序列是相依的,可以统计出该序列相依阶数。
1.2基础知识
独立性是概率论中一个重要的概念,两个事件之间的独立性是指:
一个事件的发生不影响另一个事件的发生。
这在实际问题中是很多的。
譬如在掷颗骰子,记事件A为“第一颗骰子的点数为1”,记事件B为“第二颗骰子的点数为4”。
则显然A与B的发生是相互不影响的。
若事件A与B相互独立,称A与B独立,否则A与B不独立即A与B相依。
在多维随机变量中,各分量的取值有时会相互影响,但有时会毫无影响。
譬如一个人的身高X和体重Y就会相互影响,但与收入Z一般无影响。
当两个随机变量取值互不影响时,就称它们是相互独立的。
同理,若它们的取值之间有影响,则它们之间是相依的。
1.3意义
在信息论中,多符号离散稳信源是多符号离散信源中最简单,最常用,而且也是至今为止讨论最充分、理论最成熟的一种信源。
多符号离散信源发出的消息是由一系列离散符号组成的时间(或空间)序列来表示。
例如,电报系统发出的消息,就是由“正”脉冲表示的“0”符号和“负”脉冲表示的“1”符号组成的一连串“0”、“1”符号的时间序列来表示的。
根据信息的定义,这种由离散符号的时间序列代表的消息要含有信息的前提条件是消息具有随机性,也就是每一单位时间出现的离散符号必须具有随机性。
1.4文献综述
文献[1]介绍了二叉树结点的形成与层次遍历。
文献[2]介绍了概率论中随机连续型序列与离散型序列独立性的分析。
文献[3]以实例较为详细地介绍了二叉树的分析算法与实现。
第2章基于二元树的随机变量序列相依阶数估计
2.1算法概述
根据课题要求,我们将通过二叉树的链表方式存储数据,计算二叉树每个结点的频数。
当将二进制序列读取后,按指定的维数N,从第一个字符开始一次读取N个字符,依次插入结点建立二叉树,再从第二个字符开始读取N个字符,从根结点开始依次插入,依次类推,直到循环到最后一个字符读取N个字符依次插入后,二叉树建立完成。
在插入结点的过程中,若二叉树此处结点已存在,只需次其频数增1,若结点不存在,则插入结点,并将频数增1。
当输出二叉树每个结点的频数时,利用二叉树的层次遍历。
按层次顺序访问二叉树的处理需要利用一个队列。
在访问二叉树的某一层结点时,把下一层结点指针预先记忆在队列中,利用队列安排逐层访问的次序。
因些,当访问一个结点时,将它的子女依次加到队列的队尾,然后再访问已在队列队头的结点。
这样,二叉树每个结点按照层次遍历的顺序存储在了队列中。
最后,将得到的结点频数通过计算研究,分析m元树同高度的结点空间分布以及最大独立单元和其状态空间,并且通过计算分析估计随机变量序列的相依阶数。
2.2数据结构设计
定义一个结构体来表示二叉树的结点,结构体里包含结点频数,结点符号串,结点符号,结点左右指针。
结点频数表示循环二叉树建立后,经过该结点的总次数;结点符号主要是读取二进制串时,结点符号取0表示新建结点为左孩子,符号取1表示新建结点为右孩子;
将频数、符号,结点符号串存入带根结点的二叉树中,频数的属性取了fre,标志符的属性取了flag,结点符号串的属性取了data,左子女结点指针为L,右子女结点指针为R。
并将fre,flag,data和L,R封装在结点类TreeNode中。
其链结点Node的数据结构如图2-2所示:
图2-2二叉树结点的数据结构
其中,fre为整型,flag为字符型,data为字符型指针,而L,R为指向二叉树结点TreeNode的指针。
将TreeNode定义成结构体,代码如下:
structTreeNode{//二叉树结点类定义
char*data;//结点频数
charflag;//结点标志符
intfre;//结点符号串
structTreeNode*L,*R;//左子女,右子女链域
TreeNode():
fre(0),L(NULL),R(NULL){//构造函数,初始化新建结点
data=newchar[50];
memset(data,0,50);
}
};
第3章功能函数实现
3.1二叉树结点插入
二叉树结点插入函数带两个参数,分别为当前结点、待插入结点。
该函数在设计过程中,有着一定的插入规则。
当读取字符为0,即新建结点标志符取0,若当前结点左子树为空,则新建结点插入到当前结点的左子树,同时左孩子结点频数增1,若当前结点左子树不为空,则当前左孩子结点频数增1;当读取字符为1,即新建结点标志符取1,若当前结点右子树为空,则新建结点插入到当前结点的右子树,同时右孩子结点频数增1,若当前结点右子树不为空,则当前右孩子结点频数增1。
当结点插入成功后,该结点即为下个结点插入的当前结点。
结点插入函数详细设计代码如下:
voidCreateTree(TreeNode*&Current,TreeNode*pNode){
if(pNode->flag=='0'){//当新建结点标志符取0
if(Current->L==NULL){//当前结点左子树为空
Current->L=pNode;
}
Current->L->fre+=1;//结点频数增1
Current=Current->L;//左孩子为下个新建结点插入的当前结点
}elseif(pNode->flag=='1'){//当新建结点标志符取1
if(Current->R==NULL){//当前结点右子树为空
Current->R=pNode;
}
Current->R->fre+=1;//结点频数增1
Current=Current->R;//右孩子为下个新建结点插入的当前结点
}
}
3.2二叉树的建立
二叉树的建立是一个循环的过程。
插入第一次读取的N个字符时,从根结点开始,将从存储在temp中的二进制串中读取出的N个字符作为结点依次插入二叉树,同时记录每个结点的结点符号串;第二次插入读取的N个字符时,继续是从根结点开始,依次插入二叉树。
直到将二进制串循环读取完,二叉树建立才完成。
在此过程中,每插入N个字符后,要将当前指针Current指向根结点,同时要将临时存储N个字符的变量temp1重新初始化。
二叉树的根结点不为空,且其结点标志符为空。
二叉树的建立详细设计代码如下:
char*temp1=newchar[100];
for(intj=0;jmemset(temp1,0,100);//初始化temp1
inth=1;
for(inti=0;itemp1[i]=temp[(i+j)%len];
}
Current=pRoot;//建立二叉树从根结点开始,即当前结点为根结点
for(intk=0;kpNode=newTreeNode;//创建新结点
h++;
pNode->flag=temp1[k];//读取的字符赋给新建结点的符号
for(intl=0;lpNode->data[l]=temp1[l];
pNode->data[l+1]='\0';
}
CreateTree(Current,pNode);//插入新建结点
}
}
3.3二叉树层次遍历
层次遍历是从二叉树的根结点开始,自上而下,自左向右分层依次访问树中的各个结点。
按层次顺序访问二叉树的处理需要利用一个队列。
在访问二叉树的某一层结点时,把下一层结点指针预先记忆在队列中,利用队列安排逐层访问的次序。
因些,当访问一个结点时,将它的子女依次加到队列的队尾,然后再访问已在队列队头的结点。
这样就可以实现二叉树结点的按层访问。
二叉树层次遍历详细设计代码如下:
voidLevelOrder(TreeNode*pRoot,TreeNode**queue){
intfront,rear;//front标记队列队头,rear标记队列队尾
front=-1;
rear=0;
queue[rear]=pRoot;//二叉树结点从队尾开始添加
while(front!
=rear){
front++;
if(queue[front]->L!
=NULL){//左孩子不为空,左孩子进队列
rear++;
queue[rear]=queue[front]->L;
}
if(queue[front]->R!
=NULL){//右孩子不为空时,右孩子进队列
rear++;
queue[rear]=queue[front]->R;
}
}
}
3.4程序与所实现的调度方案
#include
template
classQueue
{
public:
virtualboolIsEmpty()const=0;
virtualboolIsFull()const=0;
virtualboolFront(T&x)const=0;
virtualboolEnQueue(Tx)=0;
virtualboolDeQueue(T&x)=0;
virtualvoidClear()=0;
};
template
classSeqQueue:
publicQueue
{
public:
SeqQueue(intmSize);
~SeqQueue(){delete[]q;}
boolIsEmpty()const{returnfront==rear;}
boolIsFull()const{return(rear+1)%maxSize==front;}
boolFront(T&x)const;
boolEnQueue(Tx);
boolDeQueue(T&x);
voidClear(){front=rear=0;}
//voidLevelOrder();
private:
intfront,rear;
intmaxSize;
T*q;
};
template
SeqQueue:
:
SeqQueue(intmSize)
{
maxSize=mSize;
q=newT[maxSize];
front=rear=0;
}
template
boolSeqQueue:
:
Front(T&x)const
{
if(IsEmpty()){
cout<<"Empty"<returnfalse;
}
x=q[(front+1)%maxSize];
returntrue;
}
template
boolSeqQueue:
:
EnQueue(Tx)
{
if(IsFull()){
cout<<"Full"<returnfalse;
}
q[rear=(rear+1)%maxSize]=x;
returntrue;
}
template
boolSeqQueue:
:
DeQueue(T&x)
{
if(IsEmpty()){
cout<<"Underflow"<returnfalse;
}
front=(front+1)%maxSize;
x=q[front];
returntrue;
}
#include
#include
#include//输出格式控制
#include
#include"Queue.h"
#include
#defineN4
structTreeNode
{//二叉树结点类定义
char*data;//结点符号串
charflag;//结点标志符
intfre;//结点频数
structTreeNode*L,*R;//左子女,右子女链域
TreeNode():
fre(0),L(NULL),R(NULL)
{//构造函数,初始化新建结点
data=newchar[50];
memset(data,0,50);
}
};
TreeNode*pRoot=newTreeNode;//为根结点创建新结点
voidInsert(TreeNode*&Current,TreeNode*pNode)
{
if(pNode->flag=='0')
{//当新建结点标志符取0
if(Current->L==NULL)
{//当前结点左子树为空
Current->L=pNode;
}
Current->L->fre+=1;//结点频数增1
Current=Current->L;//左孩子为下个新建结点插入的当前结点
}
elseif(pNode->flag=='1')
{//当新建结点标志符取1
if(Current->R==NULL)
{//当前结点右子树为空
Current->R=pNode;
}
Current->R->fre+=1;//结点频数增1
Current=Current->R;//右孩子为下个新建结点插入的当前结点
}
}
intlen;
chartemp[1000000];
voidGettemp()
{//读取给定某一序列里的字符串
ifstreamifs("m8序列.txt");
charch;
inti=0;
while(!
ifs.eof())
{
ifs.get(ch);
temp[i]=ch;
i=i+1;
}
cout<<"该二进制串的长度为:
";
cout<cout<ifs.close();
len=i;
}
TreeNode*Current=newTreeNode;
voidCreatTree()
{
Gettemp();//获取二进制串
char*temp1=newchar[100];
for(intj=0;j{//循环建立二叉树
memset(temp1,0,100);//初始化temp1
inth=1;
for(inti=0;i{//存储从二进制串读取的N个字符
temp1[i]=temp[(i+j)%len];
}
Current=pRoot;//建立二叉树从根结点开始,即当前结点为根结点
for(intk=0;k{//从temp1中读取字符
TreeNode*pNode;
pNode=newTreeNode;//创建新结点
h++;
pNode->flag=temp1[k];//读取的字符赋给新建结点的符号
for(intl=0;l{//结点符号串的赋值
pNode->data[l]=temp1[l];
//cout<pNode->data[l+1]='\0';
}
Insert(Current,pNode);//插入新建结点
}
}
}
voidLevelOrder()//二叉树的层次遍历
{
cout<<"层次遍历被访问后"<if(pRoot==NULL)return;
SeqQueueQ(20);
TreeNode*p=pRoot;
Q.EnQueue(p);
while(!
Q.IsEmpty())
{
Q.DeQueue(p);
if(p!
=pRoot)
{
cout<data<<"的频数为"<<"\t"<fre<}
if(p->L!
=NULL)//若左孩子非空
{
Q.EnQueue(p->L);//左孩子入队列
}
if(p->R!
=NULL)//右孩子非空
{
Q.EnQueue(p->R);//右孩子入队列
}
}
}
voidmain()
{
CreatTree();//建立二叉树
LevelOrder();//二叉树层次遍历
}
程序运行结果参见图3-2。
图3-2策略2下的作业调度方案
3.5程序的优点
本程序是通过二叉树的链表方式存储数据,计算二叉树每个结点的频数,利用二叉树的层次遍历,输出二叉树的每个结点的频数,对于较大规模的作业都能很快地得到运行结果。
而且整个程序是基于链表和二叉树这种数据结构来实现的,编程风格一致,容易理解。
第4章总结
通过此次课程设计,使我更加扎实的掌握了有关用层次遍历访问二叉树序列频数的问题。
我们知道,其实有很多比如像素、图像等等都用到层次遍历来计算它们的频数,由此也为自己第一次踏入这门知识的领域而感到骄傲。
虽然在本次课程设计中,我们曾遇到过种种问题。
抱着对新领域的探索与求知,我们一遍一遍的检查,终于找到了问题的所在,也暴露出了前期我们在这方面上的知识欠缺与经验不足。
实践出真知,通过自己亲自动手制作,使我们掌握的知识不再是纸上谈兵。
作为一名信息专业的学生,从最开始学习的《解析几何》、《高等代数》一直到已经即将结束的《离散数学》。
我们从终于将所学习的数学知识,在计算机上得到了应用,我觉得有必要对这门课程设计中自己的所感进行一次总结,希望对初学者有一定的帮助与启迪。
为什么用面向对象的思想来设计数据结构
用面向过程的程序设计方法,来进行数据结构的设计,学习时比较容易理解与掌握。
但它的数据一般是事先具体给定的,是为其功能函数服务的,函数起着主导作用。
以函数为中心,对于函数的运用并不方便。
以排序问题为例,用于排序的函数不少,但对于一个实际问题,究竟应该选择哪一种排序函数,还必须根据实际问题的数据结构来定。
对于链表,你总不能选择冒泡函数来进行排序吧。
既然以函数为中心对于解决实际问题并不方便,那么,就只能选择以数据为中心,将为数据服务的函数与它绑定在一起,使这些服务于数据的函数成为数据的一部分。
这就是面向对象程序设计中类的概念。
致谢
到此本次课程设计终于画上了一句完美的句号,非常感谢这一次的课程设计,使我们终于将《解析几何》、《高等代数》与《离散数学》里面的知识融入到机器上,进行了一次综合的运用。
首先要感谢我的老师给我们提供了这次课程设计的机会,让我们将平时所学习的知识更加的系统化。
老师给予的指导,提供的支持与帮助,是我们能够完成本次课程设计的最主要的原因。
我还要感谢和我一起奋斗不息的小组成员,我们曾不分日夜的一起在机房里思考着,拼搏着,努力着。
大家互相鼓励,互相支持,没有你们,也就没有本次课程设计的诞生。
我还要感谢给予我们帮助的网络论坛上的朋友们,你们提供的宝贵意见,使我们的程序能够进一步的优化。
最后还要感谢在参考文献中列出的各位编者,你们所写的书在我们课程设计完成的道路上给过我们无数的指导。
这份课程设计,是我们对新领域的一次探索,我们已经上路了。
参考文献
[1]陈惠南.数据结构.北京:
清华大学出版社,2007.
[2]茆诗松.概率论.北京:
高等教育出版社,2004.
[3]洪帆.离散数学.北京:
华中科技大学出版社.2007.
附录
#include
template
classQueue
{
public:
virtualboolIsEmpty()const=0;
virtualboolIsFull()const=0;
virtualboolFront(T&x)const=0;
virtualboolEnQueue(Tx)=0;
virtualboolDeQueue(T&x)=0;
virtualvoidClear()=0;
};
template
classSeqQueue:
publicQueue
{
public:
SeqQueue(intmSi