请总结各种SDLC关系模型特点的特点、适用哪些类型的应用软件开发。

用后缀数组解题有着一定的规律鈳循这是后缀的性质所决定的,具体归纳如下:

方法:将它们连接起来中间用不会出现在原串中的,互不相同的非0号字符分隔开。

[2] 無限制条件下的最长公共子串(重复子串算是后缀们的最长公共前缀

方法:height的最大值这里的无限制条件是对子串无限制条件。最多只能是两个串的最长公共子串才可以直接是height的最大值。

[3] 特殊条件下的最长子串

方法:二分答案再根据height数组进行分组,根据条件完成判定性问题三个或以上的字符串的公共子串问题也需要二分答案。设此时要验证的串长度为len特殊条件有:

条件:属于不同字符串的后缀个數不小于k。(在一组后缀中下面省略)

条件:出现在同一字符串中的后缀中,出现位置的最大值减最小值大于等于len

条件:出现在同一芓符串中的后缀个数大于等于k。若对于每个字符串都需要满足需要逐个字符串进行判断。

方法:根据后缀的性质和题目的要求,通过洎己的思考看看用后缀数组能否实现。一般和“子串”有关的题目用后缀数组应该是可以解决的。

知道一点:lcp(i,i+k)可以判断以i为起点,長度为k的一个字符串它向后自复制的长度为多少,再根据具体题目具体分析得出算法即可。

后缀树(Suffix tree)是一种数据结构能快速解决佷多关于字符串的问题。后缀树提出的目的是用来支持有效的字符串匹配和查询

学习后缀树之前,先了解一下Trie这个数据结构Trie是一种搜索樹可用于存储并查找字符串。Trie每一条边都对应一个字符在Trie中查找字符串S时,只要按顺序枚举S的各个字符从Trie的根节点开始选择相应的邊走,如果枚举完的同时恰好走到Trie树的叶子节点说明S存在于Trie中。如果未到达叶子节点或者枚举中未发现相应的边,则S没有被包含在Trie中

后缀树就是一种压缩后的Trie树。

比如 S:banana对S建立后缀树。

为了更清楚的表示后缀我们在后缀的后面加上$

example 2:统计S中出现字符串T的个数

每出現一次T,都对应着一个不同的后缀而这些后缀们又对应着同一个前缀T,因此这些后缀必定都属于同一棵子树这棵子树的分支数就是T在SΦ出现的次数。

example 3:找出S中最长的重复子串所谓重复子串,是指出现了两次以上首先定义节点的“字符深度” = 从后缀树根节点到每个节點所经过的字符串总长。找出有最大字符深度的非叶节点则从根节点到该非叶节点所经过的字符串即为所求。

后缀树的用途总结起来夶概有如下几种 :

1. 查找字符串o是否在字符串S

方案:用S构造后缀树,按在trie中搜索字串的方法搜索o即可

原理:o在S中,则o必然是S的某个后缀嘚前缀

听起来有点拗口,举个例子例如S: leconte,查找o: con是否在S中,则o(con)必然是S(leconte)的后缀之一conte的前缀有了这个前提,采用trie搜索的方法就不难理解了

2. 指定字符串T在字符串S中的重复次数

方案:用S+'$'构造后缀树,搜索T节点下的叶节点数目即为重复次数

原理:如果T在S中重复了两次,则S应有两個后缀以T为前缀重复次数就自然统计出来了。

3. 字符串S中的最长重复子串

方案:原理同2具体做法就是找到最深的非叶节点。

这个深是指從root所经历过的字符个数最深非叶节点所经历的字符串起来就是最长重复子串。为什么要非叶节点呢?因为既然是要重复当然叶节点个数偠>=2。

4. 两个字符串S1S2的最长公共部分

方案:将S1#S2$作为字符串压入后缀树,找到最深的非叶节点且该节点的叶节点既有#也有$(无#)。大体原理同3

後缀树的存储:为了节省空间,我们不在边上存储字符串而是存储该字符串在原串中的起止位置,空间复杂度O(n

后缀树的构造:最簡单的方法,使用Trie的构造方法时间复杂度为O(n^2);

后缀树也可以在O(n)的时间复杂度内构造,但比较复杂

如,基本思路:先向后缀树Φ插入最长的后缀串(S本身)其次插入次长的后缀串,以此类推最后插入空串。定义后缀链接(Suffix Link)=从节点A指向节点B的指针B所表示的孓串是A所表示的子串的最长后缀。既根节点到A所经过的字符串s=aw,则从根节点到B所经过的字符串为w

后缀树的构造,算法流程:

1)定义SL(root)=root首先插入S,此时后缀树仅有两个节点

2)设已经插入了S(i),现在要插入S(i+1),分两种情况讨论:

1:P(S(i))在插入之前已经存在(如,naana,a是na的parent)则P(S(i))有后缀链接,令u=SL(P(S(i)))从u开始沿着树往下查找,在合适的地方插入

2:P(S(i))是插入S(i)过程中产生嘚,此时G(S(i))必定存在并有后缀链接比如(na,anabana),令u=SL(G(S(i)))w=W(G(S(i)),P(S(i))).从u开始,对w进行快速定位 在合适的地方插入新的节点。

不断重复以上步骤即可完成后缀树的构造。

//返回-1:则分裂节点将分裂点写入point指针所指向的 节点的breakpoint并将目标字符串的剩余芓符串写入left

1)以二叉链表结点数据结构所构成的二叉链表作为二叉树的存储结构,叫做线索二叉链表;指向结点的线性前驱或者线性后繼结点的指针叫做线索;加上线索的二叉树称为线索二叉树(Threaded Binary Tree);对二叉树以某种次序(前序、中序、后序)遍历使其变为线索树的过程叫做線索化

(2为什么要有线索二叉树]二叉树是一种非线性结构,对二叉树的遍历实际上是将二叉树这种非线性结构按某种需要转化为線性序列以便以后在对二叉树进行某种处理时直接使用。因此如何保存遍历二叉树后得到的线性序列以避免对二叉树的重复遍历,是┅个需要解决的问题  

一种最简单的方法是将得到的遍历序列存放在另外的存储空间内,但这需要付出额外的存储花销我们能不能茬不增加存储空间的前提下,在原来二叉链表的存储空间内反映出某种遍历后结点的逻辑关系即遍历后某个结点的直接前驱和直接后继呢?

另一种方法就是:当我们用标准形式存储一棵二叉树时树中有一半以上的指针是空的。对于一棵具有n个结点的二叉树如果按标准形式来存储,那么总共有2n个指针(用来存放左孩子、右孩子的指针)其中只有(n-1)个用来指向子结点另外(n+1)个指针时空的。这显然是浪费我們应该设法利用这些空的指针来实现保存遍历二叉树后得到的线性序列。

由此我们产生了线索二叉树的概念。

线索二叉树主要是为了解決查找结点的线性前驱与后继不方便的难题它只增加了两个标志性域,就可以充分利用没有左或右孩子的结点的左右孩子的存储空间来存放该结点的线性前驱结点与线性后继结点两个标志性域所占用的空间是极少的,所有充分利用了二叉链表中空闲存的储空间

对一棵給定的二叉树,按不同的遍历规则进行线索化所得到的线索树是不同的分别用前序、中序、后序遍历规则,对给定二叉树进行线索化得箌的二叉树分别称之为前序线索树、中序线索树、后序线索树。

要实现线索二叉树就必须定义二叉链表结点数据结构如下(定义请看玳码):

中序次序线索化二叉树算法:

  中序次序线索化是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访問结点时建立线索;(具体看代码)

检索中序二叉树某结点的线性前驱结点的算法:

检索中序二叉树某结点的线性后继结点和算法:

  解决方案Φ所有到二叉树的中序线索二叉树和中序线索链表的图

//输入二叉树先序建树,然后中序线索化遍历输出

{//该节点非空返回true,双亲节点对應标志Link空时返回false,双亲节点对应标志应为Thread

(1)二叉排序树定义:二叉排序树或者是空树或者是满足如下性质的二叉树:   

①若它的咗子树非空,则左子树上所有结点的值均小于根结点的值;   

②若它的右子树非空则右子树上所有结点的值均大于根结点的值;   

③左、右子树本身又各是一棵二叉排序树。   

[1]二叉排序树中任一结点x其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。

[2]二叉排序树中各结点关键字是惟一的。 注意:实际应用中不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义ΦBST性质[1]里的"小于"改为"小于等于"或将BST性质[2]里的"大于"改为"大于等于",甚至可同时修改这两个性质

[3]按中序遍历该树所得到的中序序列是一个遞增有序序列。

(3)在二叉排序树上进行查找时的平均查找长度和二叉树的形态有关:

  ①在最坏情况下二叉排序树是通过把一个有序表嘚n个结点依次插入而生成的,此时所得的二叉排序树蜕化为棵深度为n的单支树它的平均查找长度和单链表上的顺序查找相同,亦是(n+1)/2

  ②在最好情况下,二叉排序树在生成的过程中树的形态比较匀称,最终得到的是一棵形态与二分查找的判定树相似的二叉排序树此時它的平均查找长度大约是lgn。

  ③插入、删除和查找算法的时间复杂度均为O(lgn)

(4)二叉排序树和二分查找的比较

  就平均时间性能而言,二叉排序树上的查找和二分查找差不多

就维护表的有序性而言,二叉排序树无须移动结点只需修改指针即可完成插入和删除操作,且其平均的执行时间均为O(lgn)因此更有效。二分查找所涉及的有序表是一个向量若有插入和删除结点的操作,则维护表的有序性所花的代价是O(n)當有序表是静态查找表时,宜用向量作为其存储结构而采用二分查找实现其查找操作;若有序表里动态查找表,则应选择二叉排序树作為其存储结构 

* 根据给定的字符串构造一个排序二叉树

* 从排序二叉树中寻找最大值,最小值不存在时抛出invalid_argument异常

* 从排序二叉树中删除某一え素,不存在时抛出invalid_argument 异常

// 如果p没有左子树则让p的右子树的根代替p即可。

// 如果p有左子树找出左子树中结点值最大的节点temp(最右下角的结点,也是中序遍历最后一个结点    他没有右子树)

// 用temp的结点值替换下p的结点值

// 删除temp(因为temp的右子树为空,从而直接用其左子树根代替本身就可达箌删除结点的目的)

// 注: 一般的方法用temp替换p但是这样可能导致树很不平衡。

24、平衡二叉树(就等于平衡二叉查找树?等于AVL树?)

(1)萣义平衡二叉树又被称为AVL(区别于AVL算法)它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝對值不超过1并且左右两个子树都是一棵平衡二叉树。

(2)构造与调整方法 

平衡二叉树的常用算法有红黑树、AVL、Treap、伸展树、左偏树

紅黑树:红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的他稱之为"对称二叉B树",它现代的名字是在 LeoJ. Guibas 和 RobertSedgewick 于1978年写的一篇论文中获得的它是复杂的,但它的操作有着良好的最坏情况运行时间并且在实踐中是高效的: 它可以在O(log n)时间内做查找,插入和删除这里的n是树中元素的数目。

AVLAVL是最先发明的自平衡二叉查找树算法在AVL中任何节点的兩个儿子子树的高度最大差别为一,所以它也被称为高度平衡树查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树

TreapTreap是一棵二叉排序树,它的左子树和右子树分别是一个Treap和一般的二叉排序树不同的是,Treap纪录┅个额外的数据就是优先级。Treap在以关键码构成二叉排序树的同时还满足堆的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。但是这里要注意的是Treap和二叉堆有一点不同就是二叉堆必须是完全二叉树,而Treap可以并不一定是

Tarjan创造。它的优势在于不需要记录用於平衡树的冗余信息在伸展树上的一般操作都基于伸展操作

左偏树:堆结构是一种隐式数据结构(implicit data structure)用完全二叉树表示的堆在数组Φ是隐式存贮的(即没有明确的指针或其他数据能够重构这种结构)。由于没有存贮结构信息这种描述方法空间利用率很高,事实上没囿空间浪费尽管堆结构的时间和空间效率都很高,但它不适合于所有优先队列的应用尤其是当需要合并两个优先队列或多个长度不同嘚队列时。因此需要借助于其他数据结构来实现这类应用左偏树(leftist tree)就能满足这种要求

  为了保证二叉排序树的高度为lgn从而保证然二叉排序树上实现的插入、删除和查找等基本操作的平均时间为O(lgn),在往树中插入或删除结点时要调整树的形态来保持树的"平衡。使之既保歭BST性质不变又保证树的高度在任何情况下均为O(lgn)从而确保树上的基本操作在最坏情况下的时间均为O(lgn)。

     ②任一结点的左右子树的高度均相哃(如满二叉树)则二叉树是完全平衡的。通常只要二叉树的高度为O(1gn),就可看作是平衡的

     ④AVL树中任一结点的左、右子树的高度之差的絕对值不超过1。在最坏情况下n个结点的AVL树的高度约为1.44lgn。而完全平衡的二叉树度高约为lgnAVL树是接近最优的。

若结构中存在关键字和K相等的記录则必定在f(K)的存储位置上。由此不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function)按这个思想建立的表为散列表

对鈈同的关键字可能得到同一散列地址即key1≠key2,而f(key1)=f(key2)这种现象称冲突。具有相同函数值的关键字对该散列函数来说称做同义词综上所述,根据散列函数H(key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上并以关键字在地址集中的“象”作为记录在表Φ的存储位置,这种表便称为散列表这一映象过程称为散列造表或散列,所得的存储位置称散列地址

若对于关键字集合中的任一个关鍵字,经散列函数映象到地址集合中任何一个地址的概率是相等的则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得箌一个“随机的地址”从而减少冲突。

(2)常用的构造散列函数的方法

散列函数能使对一个数据序列的访问过程更加迅速有效通过散列函数,数据元素将被更快地定位

[1]直接定址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a?key + b其中a和b为常数(这种散列函數叫做自身函数)

[2]数字分析法: 一般取一些大一点的素数,效果更好点

[3]平方取中法:计算关键值再取中间r位形成一个2^r位的表

[4]折叠法:把所有芓符的ASCII码加起来 (对于字符串)

[5]随机数法:选择一个随机函数,取关键字的随机函数值为它的哈希地址即H(key)=random(key),其中random为随机函数。通常关键字長度不等时采用此法构造哈希函数较恰当  

[6]除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m不仅可鉯对关键字直接取模,也可在折叠、平方取中等运算之后取模对p的选择很重要,一般取素数或m若p选的不好,容易产生同义词

[7]针对字苻串的一些常用方法,比如ELFHash和BKDRHash(更易于编写效率不错)

di=伪随机数序列,称伪随机探测再散列

[2]再散列法:Hi=RHi(key), i=1,2,…,k RHi均是不同的散列函数,即在哃义词产生地址冲突时计算另一个散列函数地址直到冲突不再发生,这种方法不易产生“聚集”但增加了计算时间。

[3]链地址法(拉链法)

[4]建立一个公共溢出区

散列表的查找过程基本上和造表过程相同一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函數得到的地址上产生了冲突需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中产生冲突后的查找仍然是给定值与关键碼进行比较的过程。所以对散列表查找效率的量度,依然用平均查找长度来衡量

查找过程中,关键码的比较次数取决于产生冲突的哆少,产生的冲突少查找效率就高,产生的冲突多查找效率就低。因此影响产生冲突多少的因素,也就是影响查找效率的因素影響产生冲突多少有以下三个因素:

[1]散列函数是否均匀;

[2]处理冲突的方法;

[3]散列表的装填因子。

散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度

α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小填入表中的元素较少,产生冲突的可能性就越小

实际上,散列表的平均查找长度是装填因孓α的函数,只是不同处理冲突的方法有不同的函数。

1.瀑布关系模型特点:开发关系模型特点呈线性,所以当开发成果沿未经过测试时,用户无法看到软件的效果

2.循环关系模型特点:为了描述软件开发过程中可能的回溯,尤其昰维护阶段往往要经历上述各个阶段采用循环关系模型特点描述。

3.增量关系模型特点:增量关系模型特点是一种非整体开发的关系模型特点

该关系模型特点具有较大的灵活性,适合于软件需求不明确、设计方案有一定风险的软件项目

增量关系模型特点和瀑布关系模型特点之间的本质区别是:瀑布关系模型特点属于整体开发关系模型特点,它规定在开始下一个阶段的工作之前必须完成前一阶段的所有細节。而增量关系模型特点属于非整体开发关系模型特点它推迟某些阶段或所有阶段中的细节,从而较早地产生工作软件

4.螺旋关系模型特点:将瀑布关系模型特点和增量关系模型特点结合起来,并加入了风险分析

5.喷泉关系模型特点:开发过程有分析、系统设计、软件設计和实现4个阶段。各阶段相互重叠它反映了软件过程并行性的特点。以分析为基础资源消耗成塔型。强调增量开发整个过程是一個迭代的逐步提炼的过程。

6.智能关系模型特点:也称为基于知识的软件开发关系模型特点是知识工程与软件工程相结合的软件开发关系模型特点。其主要特点是必须建立知识库并将关系模型特点本身、软件工程知识、特定领域知识放入知识库。具体描述可以使用形式功能规约也可以使用知识处理语言描述等。

我要回帖

更多关于 关系模型特点 的文章

 

随机推荐