Uploaded by xinyanqi427816

lab2 take home

advertisement
我们将在这个实验室里研究 DNA,所以让我们介绍一些我们将使用的术语。
一个 DNA 分子或链是一个被称为碱基或核苷酸(这些都是同义词)的分子单元序列。有四
种类型,分别表示 A(腺嘌呤)、C(胞嘧啶)、G(鸟嘌呤)和 T(胸腺嘧啶)。我们熟悉
的人类 DNA 双螺旋分子的每条链都包含大约 30 亿个这样的核苷酸。双螺旋中有两条 DNA
链,每一条都是另一条的互补副本:一条链上的 "A "总是与另一条链上的 "T "配对,而 "C
"总是与 "G "配对。有时我们称这些为碱基对。因为如果我们有另一条链的序列,重建一条
链的碱基序列是微不足道的,所以我们真的只需要研究一条链就能了解 DNA 的某一特定部
分的作用。
在我们的遗传密码中,DNA 的三个核苷酸(即三个 "字母")构成一个密码子,并指定一个
氨基酸。有 20 种常见的氨基酸类型。一个蛋白质分子只不过是一长串的氨基酸。氨基酸决
定了蛋白质的形状,从而决定了它在制造蛋白质的细胞中的功能。与蛋白质相比,DNA 不
会迅速磨损。这使得 DNA 很适合在细胞中进行数据存储。DNA 本质上是一种生物数据结构。
下表 2.1 中的每个条目都列出了一个密码子--代表 DNA 核苷酸的三个大写字母,以及一个氨
基酸或 "停止 "一词。例如,TCT 指的是氨基酸丝氨酸。停止密码子,即 TAA、TAG 和 TGA,
告诉细胞的翻译机器已经到达了基因的终点。请注意,一个以上的密码子可以指定同一个氨
基酸,因此一个以上的 DNA 序列可以指定同一个蛋白质。例如,蛋氨酸-异亮氨酸-苯丙氨酸
-天冬氨酸-甘氨酸的蛋白质片段由 ATGATCTTTGACGGG 编码,也可以由 ATGATTTTTGATGGT 编
码。
现在假设我们有一部分 DNA,我们希望找出它所编码的蛋白质。由于我们不知道我们是否
有 DNA 序列的开头,而且我们很可能有中间某个地方的一块,我们不知道从哪里开始读。
哪个碱基对是第一个碱基对?我们从哪一端开始读?该片段是在一个密码子的边界正确开
始,还是从一个缺失的密码子的最后一个或两个单位开始?正如你所想象的,选择在哪里开
始翻译和在哪里停止是很重要的(我们已经知道在哪里停止,因为有 "停止代码",TAA,TAG
和 TGA)。
可以用到的函数
#include <string.h>
char * strncat(char * s1, const char * s2, size_t n)。
strncat()函数将不超过 n 个字节(一个空字节和它后面的任何字节不被追加)从 s2 指向的字
符串追加到 s1 指向的字符串的结尾。s2 的初始字节覆盖了 s1 末尾的空字节。一个结束的空
字节总是被附加到结果中。strncat()函数返回 s1。
char * strdup(const char * s1);
strdup()函数复制 s1 所指向的字符串,并返回一个指向新字符串的指针。返回的指针可以被
传递给 free()。如果不能创建新的字符串,则返回一个空指针。strdup()函数在成功时返回一
个指向新字符串的指针。[注意:Visual Studio 编译器可能会抱怨 strdup()函数的问题。如果
是这样,请尝试用微软的版本_strdup 来代替它。]
size_t strlen(const char * s)。
strlen()函数计算并返回 s 所指向的字符串中的字节数,不包括结束的空字节。
int strncmp(const char * s1, const char * s2, size_t n);
strncmp()函数对 s1 指向的字符串和 s2 指向的字符串进行不超过 n 个字节的比较(空字节之
后的字节不作比较)。成功完成后,如果 s1 指向的可能为空的字符串大于、等于或小于 s2
指向的可能为空的字符串,strncmp()返回一个大于、等于或小于 0 的整数。
char * strncpy(char * s1, const char * s2, size_t n)。
strncpy()函数将不超过 n 个字节(空字节之后的字节不被复制)从 s2 所指向的字符串复制到
s1 所指向的字符串。如果 s2 所指向的字符串短于 n 个字节,空字节将被追加到 s1 所指向的
字符串中的副本中,直到全部写完 n 个字节。strncpy()函数返回 s1。
char * strstr(const char * s1, const char * s2)。
strstr()函数在 s1 所指向的字节序列中找到 s2 所指向的字节序列的第一次出现(不包括结束
的空字节)。成功完成后,strstr()返回一个指向所定位子串的指针,如果没有找到该字符串,
则返回一个空指针。如果 s2 指向一个零长度的字符串,该函数返回 s1。
在 MacLeod 的二楼实验室里发现了一滴血,一个不可替代的古董示波器丢失。加拿大皇家
骑警到达后发现没有人受伤。他们从这滴血中提取了部分 DNA 样本,并将其带到校园实验
室。
你和你的伙伴在校外喝咖啡,阅读唐纳德 -克努斯的《计算机编程的艺术》,并关注
stackoverflow.com(链接到外部网站。),这时你的电话响了。来电者是你的一个朋友,她
在校园实验室为皇家骑警工作,她很苦恼。一个实习生正在给什么东西编码,发生了一场名
副其实的灾难,她喘着气说。她告诉你,这个实习生去年选修了 CPSC 259,并决定重写实验
室的 DNA 匹配程序,而这个程序恰好是用 C 语言编写的。通常随叫随到处理这种电脑事情
的实验室助理正在休假,无法联系上。你的朋友提到了你的名字,加拿大皇家骑警希望尽快
完成初步分析。
在商店门口迎接你的皇家骑警巡逻车将你带到实验室。一旦你到了那里,你就坐在其中一台
电脑前,评估一下。可执行文件不见了,但你找到了法医技术人员用来编写程序的旧的迭代
框架。你还了解到,DNA 已经被分析了,结果被编码为一串代表核苷酸片段的字符。加拿
大皇家骑警有一些可能的嫌疑人在过去也提供过 DNA,他们的候选样本也在同一个文件中。
你和你的伙伴松了一口气,因为你意识到用于匹配样本的算法非常简单,你把你的任务分解
如下。
在这里下载我们为你创建的框架 在这里下载。. 解压缩该文件夹。这是一个部分实现的
Visual Studio 2019 项目。你需要实现的代码在文件 dna.c 中。你需要完成的唯一代码是在
analyze_segments 和 calculate_scores 函数中。
由于这是该程序的早期迭代,它非常简单,只有一个命令行界面。没有 GUI,即图形用户界
面。
你的程序一开始就为用户提供了一个菜单。菜单的选择是。1. 载入文件,2.进行分析,3.
退出。用户必须输入他们选择的数字。其他的都会被忽略,而菜单会再次提供。你没有责任
知道菜单代码是如何工作的,但是如果你有兴趣,可以看一看
一、
如果用户选择了 1,你的程序会要求用户提供 DNA 数据文件的名称,然后尝试打开该文件
并将其内容复制到一些动态分配的内存中。如果程序不能打开该文件,它将打印一个适当的
信息并返回主菜单。[注意,我们在本项目的资源文件夹中为你提供了 3 个测试文件:
long_sample.txt、short_sample.txt 和 perfect_match.txt。为了帮助你确定你的实现的正确性,
还提供了每个文件的正确输出结果] 。
DNA 数据文件将始终与我们在这里描述的完全一样。该文件将永远不会由其他东西组成。
我们提供了打开该文件并将其复制到动态存储器的代码。该文件包含一个样本段和一个或多
个候选段,候选段的长度至少与样本段相同。候选段不会比样本段短。所有的段都以字符串
的形式存储,以换行符结束。你可以不对样本的长度做任何假设。它可能有数百万个字符长。
候选片段的长度总是等于或长于在犯罪现场采集的样本,绝不会短于
二、如果用户选择 3,程序执行结束(我们已经为你写好了这个)。
三、如果用户选择了 2,而一个文件还没有被打开并复制到堆中,则什么也不会发生。 菜
单会再次询问用户要做什么(我们已经为你写好了)。
四、如果用户选择了 2,而一个文件已经被打开并复制到了堆中,程序会立即开始分析(你
需要写出这样的代码)。
1.寻找样本和每个候选序列之间的完全匹配。 测试每个候选序列。 在测试完全匹配时,你
必须测试样本的整个长度,甚至任何尾随的核苷酸。当一个样本和一个候选序列的长度完全
相同并且包含完全相同的字符时,就是完全匹配。每当你的程序找到一个完全匹配,它必须
向标准输出打印一条信息,说明哪个(些)候选序列是一个完全匹配。
其中 XXX,和 YYY 是根据它们在文本文件中提供的候选人名单(当然不包括样本)中的顺序
确定的。如果有一个或多个完美匹配,在你为每个完美匹配打印这个完美匹配信息后,你不
需要再打印其他东西或计算其他分数,你的程序应该返回菜单。
2.如果没有完全匹配,那么必须为每个样本-候选人对找到一个最佳匹配。程序必须给每个
候选人打分。
(1)每个分数从 0 开始。
(2)让 LENGTH 成为样本中密码子(3 个核苷酸组成的组)的数量(记住,样本的长度总是相
等的,或者比候选者短)。忽略样本中任何尾随的核苷酸(可能有 1 或 2 个,但不能多)。
换句话说,如果(样本长度%3)不等于零,我们就忽略样本中(样本长度%3)的最后一个
核苷酸。[%是模数运算符。3 % 3 = 0; 4 % 3 = 1; 7 % 3 = 1; 8 % 3 = 2.
(3)对于每个 LENGTH 密码子,如果两个密码子(样本和候选)完全相同,则在分数上加 10。
否则,如果这两个密码子不同,但指定了相同的氨基酸,则在得分上加 5 分。
(4)对于你刚才比较的每一个 LENGTH 密码子,如果它们不完全相同,就是说你刚才没有加
10 分,而且它们没有指定相同的氨基酸,就是说你刚才也没有加 5 分,你必须分别检查密
码子的 3 个核苷酸。对于密码子中的 3 个核苷酸中的每一个,如果样本和候选者中的字符是
相同的,就在分数上加 2。如果这 2 个字符属于一个匹配的碱基对(A 和 T,或 C 和 G),
则得分加 1。否则,在得分上加 0。储存结果。
(5)由于候选基因总是比样本长,在你检查了第一个长度的密码子之后,你必须将样本沿着
候选基因的长度移动 1 个密码子(也就是 3 个核苷酸,也就是 3 个字母),然后检查这个新
的排列的分数(所以现在你要将样本的第一个密码子,或者 3 个字母,与候选基因的第二个
密码子(字母 4、5、6)对齐,或者使用 1 的密码子偏移)。储存分数,然后再做一次,例
如,使用 2 的密码子偏移量。 不断地将样本深入到候选的密码子中,一次一个密码子,检
查分数,直到它不再适合。(记住要忽略尾随的核苷酸)。) 一旦样本超出了候选者的长度,
你的程序就必须停止移位和检查该候选者的分数。这个候选者的分数是所有这些结果中最高
的。下面是你对每个候选者所要做的事情的一个可视化表示。
(6)输出所有候选人的分数,每个都应该如下格式:
Candidate number XXX matches with a score of ###.
Download