登录
首页精彩阅读从Trie树谈到后缀树之后缀树的C++简单实现_数据分析师
从Trie树谈到后缀树之后缀树的C++简单实现_数据分析师
2014-11-19
收藏

从Trie树谈到后缀树之后缀树的C++简单实现_数据分析师

本程序只是简单实现了后缀树的构造,查询等基本的操作。如果此文能引出读者更好的suffixtree 的实现,此文的价值便更甚了。谢谢。

suffix-tree的c++实现

    完整源码如下,由于注释已经够详细,便不再多说什么了:

   

  1. // suffer tree.cpp : 定义控制台应用程序的入口点。
  2. //copyright@ 2011 July && 匿名
  3. //1、参考了他人的程序,但不知道原作者是谁。
  4. //如果你知道,请立马联系我,一定把原作者的大名署上,谢谢。
  5. //2、主函数没有写全了,读者视需要自己补上吧。
  6. #include "stdafx.h"
  7. #ifndef __SUFFIXTREE_H
  8. #define __SUFFIXTREE_H
  9. #include 
  10. #include 
  11. #include 
  12. usingnamespacestd;
  13. usingstd::list;
  14. usingstd::vector;
  15. //对于叶节点,通过m_nActiveLen和m_nEdgeLabelEndPos可以得到节点对应的字符串.对于分支节点,也是如此.
  16. structtagSuffixNode
  17. {
  18. public:
  19. tagSuffixNode* m_tpChild;//子节点,如果为0,说明是叶子节点
  20. tagSuffixNode* m_tpParent;//父节点,根节点的父节点为0
  21. tagSuffixNode* m_tpLeftSibling;//左兄弟
  22. tagSuffixNode* m_tpRightSibling;//右兄弟
  23. tagSuffixNode* m_tpMostRightChild;//最右子节点
  24. tagSuffixNode* m_tpSuffixLink;//指向当前节点表示的子串的最大后缀所对应的分支节点
  25. intm_nActiveLen;//节点代表的字符串的长度.
  26. intm_nEdgeLabelStartPos;//入边开始字符的下标.对于分支节点,只是用来表示边对应的字符串是什么,并不表示其在子孙叶节点表示的串中对应位置的字符在整个串中的下标.
  27. intm_nEdgeLabelEndPos;//入边结束字符的下标
  28. boolm_bIsLeaf;//是否是叶节点
  29. charm_cIndex;//test
  30. public:
  31. //全部初始化为0
  32. voidinit()
  33. {
  34. m_tpChild = 0;
  35. m_tpParent = 0;
  36. m_tpLeftSibling = 0;
  37. m_tpRightSibling = 0;
  38. m_tpMostRightChild = 0;
  39. m_tpSuffixLink = 0;
  40. m_nEdgeLabelStartPos = 0;
  41. m_nEdgeLabelEndPos = 0;
  42. m_nActiveLen = 0;
  43. m_bIsLeaf =true;
  44. }
  45. };
  46. classCSuffixTree
  47. {
  48. public:
  49. CSuffixTree(char*str);
  50. ~CSuffixTree();
  51. voiddeleteTree();
  52. voidconstruct();
  53. voidreset(char*str);
  54. intsearch(char*str);
  55. tagSuffixNode* getTree();
  56. voidprintTree();
  57. voidtest();
  58. private:
  59. tagSuffixNode* __allocNode();
  60. tagSuffixNode* __findChildBeginWithChar(tagSuffixNode* node,charc);
  61. void__printHelper(tagSuffixNode* node,intlevel);
  62. private:
  63. intm_nActiveLen;
  64. intm_nStrLen;//字符串长度
  65. tagSuffixNode* m_tpRoot;//根节点
  66. tagSuffixNode* m_tpActiveNode;//活动节点
  67. char*m_cpInternalStr;//字符串内存存储
  68. list m_tagNodeList;//保存分配的节点的指针
  69. vector m_tagFromNodeVec;//保存还未确定后缀指针的分支节点的指针,用于判定suffix link
  70. vector m_tagToNodeVec;//保存所有分支节点
  71. #ifdef DEBUG
  72. charm_cIndex;
  73. #endif
  74. };
  75. #endif //
  76. //#include "suffixtree.h"
  77. #include 
  78. #include 
  79. #include 
  80. #include 
  81. #include 
  82. usingnamespacestd;
  83. CSuffixTree::CSuffixTree(char*str)
  84. :m_nActiveLen(0),
  85. m_tpRoot(0),
  86. m_tpActiveNode(0)
  87. {
  88. m_nStrLen = strlen(str) + 1;
  89. m_cpInternalStr =newchar[m_nStrLen+1];
  90. sprintf(m_cpInternalStr,"%s#", str);
  91. #ifdef DEBUG
  92. m_cIndex ='A';
  93. #endif
  94. }
  95. CSuffixTree::~CSuffixTree()
  96. {
  97. deleteTree();
  98. delete[] m_cpInternalStr;
  99. }
  100. voidCSuffixTree::deleteTree()
  101. {
  102. list::iterator iter = m_tagNodeList.begin();
  103. for(; iter != m_tagNodeList.end(); ++iter)
  104. {
  105. delete*iter;
  106. }
  107. m_tagNodeList.clear();
  108. }
  109. voidCSuffixTree::reset(char*str)
  110. {
  111. deleteTree();
  112. inttmp = strlen(str);
  113. if(tmp+1 > m_nStrLen)
  114. {
  115. m_nStrLen = tmp+1;
  116. delete[] m_cpInternalStr;
  117. m_cpInternalStr =newchar[m_nStrLen+1];
  118. }
  119. else
  120. {
  121. m_nStrLen = tmp+1;
  122. }
  123. sprintf(m_cpInternalStr,"%s#", str);
  124. m_nActiveLen = 0;
  125. m_nStrLen = 0;
  126. m_tpActiveNode = 0;
  127. m_tpRoot = 0;
  128. m_tagFromNodeVec.clear();
  129. //reconstruct tree for new string
  130. construct();
  131. }
  132. //suffixTree之构造
  133. voidCSuffixTree::construct()
  134. {
  135. m_tpRoot = __allocNode();
  136. if(m_tpRoot == 0)
  137. {
  138. #ifdef DEBUG
  139. printf("__allocNode error!\n");
  140. #endif
  141. return;
  142. }
  143. m_nActiveLen = 0;
  144. m_tpRoot->m_nActiveLen = 0;
  145. //initial active node
  146. m_tpActiveNode = m_tpRoot;
  147. m_tagToNodeVec.push_back(m_tpRoot);
  148. for(inti = 0; i
  149. {
  150. #ifdef DEBUG
  151. printf("\ninsert %s\n", &(m_cpInternalStr[i]));
  152. printf("active node:[%c]\n", m_tpActiveNode->m_cIndex);
  153. #endif
  154. //判断是否有后继节点
  155. if(m_tpActiveNode->m_tpSuffixLink != 0)
  156. {
  157. m_tpActiveNode = m_tpActiveNode->m_tpSuffixLink;
  158. m_nActiveLen--;
  159. }
  160. intpos = i;
  161. #ifdef DEBUG
  162. printf("new active node:[%c]\n", m_tpActiveNode->m_cIndex);
  163. printf("pos:%d\n", pos);
  164. printf("active length:%d\n", m_nActiveLen);
  165. #endif
  166. while(true)
  167. {
  168. //查找以当前后缀串的开始字符开始的子节点
  169. tagSuffixNode* node = __findChildBeginWithChar(m_tpActiveNode, m_cpInternalStr[i+m_nActiveLen]);
  170. //未找到以suffix[i]的开始字符开头的节点
  171. if(node == 0)
  172. {
  173. #ifdef DEBUG
  174. printf("__findChildBeginWithChar null\n");
  175. #endif
  176. tagSuffixNode* child = __allocNode();
  177. //设置开始、结束位置的下标
  178. child->m_nEdgeLabelStartPos = pos;
  179. child->m_nEdgeLabelEndPos = m_nStrLen-1;
  180. //设置叶节点代表的后缀串的长度
  181. child->m_nActiveLen = m_nStrLen - i;
  182. //设置父节点
  183. child->m_tpParent = m_tpActiveNode;
  184. if( m_tpActiveNode->m_tpChild == 0)
  185. {
  186. m_tpActiveNode->m_tpChild = child;
  187. m_tpActiveNode->m_tpMostRightChild = child;
  188. }
  189. else
  190. {
  191. m_tpActiveNode->m_tpMostRightChild->m_tpRightSibling = child;
  192. child->m_tpLeftSibling = m_tpActiveNode->m_tpMostRightChild;
  193. m_tpActiveNode->m_tpMostRightChild = child;
  194. }
  195. break;
  196. }
  197. else
  198. {
  199. #ifdef DEBUG
  200. printf("__findChildBeginWithChar ok\n");
  201. printf("node start:%d\n", node->m_nEdgeLabelStartPos);
  202. printf("node end:%d\n", node->m_nEdgeLabelEndPos);
  203. printf("node index:%c\n", node->m_cIndex);
  204. #endif
  205. //TODO
  206. //确定 m_nMinDistance
  207. intedgeStart = node->m_nEdgeLabelStartPos;
  208. intstrStart = i + m_nActiveLen;
  209. boolsplit =false;
  210. for(; edgeStart<=node->m_nEdgeLabelEndPos; edgeStart++, strStart++)
  211. {
  212. if( m_cpInternalStr[edgeStart] != m_cpInternalStr[strStart])
  213. {
  214. split =true;
  215. break;
  216. }
  217. }
  218. if(!split)
  219. {
  220. m_tpActiveNode = node;
  221. m_nActiveLen += node->m_nEdgeLabelEndPos - node->m_nEdgeLabelStartPos + 1;
  222. pos += node->m_nEdgeLabelEndPos - node->m_nEdgeLabelStartPos + 1;
  223. continue;
  224. }
  225. else
  226. {
  227. tagSuffixNode* parent = node->m_tpParent;
  228. //new branch node
  229. tagSuffixNode* branch = __allocNode();
  230. branch->m_bIsLeaf =false;
  231. branch->m_nEdgeLabelStartPos = node->m_nEdgeLabelStartPos;
  232. branch->m_nEdgeLabelEndPos = edgeStart-1;
  233. branch->m_nActiveLen = parent->m_nActiveLen + (branch->m_nEdgeLabelEndPos - branch->m_nEdgeLabelStartPos + 1);
  234. //original node
  235. node->m_nEdgeLabelStartPos = edgeStart;
  236. tagSuffixNode* info = __allocNode();
  237. info->m_nEdgeLabelStartPos = strStart;
  238. info->m_nEdgeLabelEndPos = m_nStrLen - 1;
  239. info->m_nActiveLen = branch->m_nActiveLen + (info->m_nEdgeLabelEndPos - info->m_nEdgeLabelStartPos + 1);
  240. branch->m_tpParent = parent;
  241. branch->m_tpRightSibling = parent->m_tpChild;
  242. parent->m_tpChild->m_tpLeftSibling = branch;
  243. parent->m_tpChild = branch;
  244. node->m_tpLeftSibling->m_tpRightSibling = node->m_tpRightSibling;
  245. if( node->m_tpRightSibling != 0)
  246. {
  247. node->m_tpRightSibling->m_tpLeftSibling = node->m_tpLeftSibling;
  248. }
  249. else
  250. {
  251. parent->m_tpMostRightChild = node->m_tpLeftSibling;
  252. }
  253. branch->m_tpChild = info;
  254. branch->m_tpMostRightChild = node;
  255. info->m_tpRightSibling = node;
  256. info->m_tpParent = branch;
  257. node->m_tpParent = branch;
  258. node->m_tpLeftSibling = info;
  259. node->m_tpRightSibling = 0;
  260. //设置节点的suffix link
  261. boolsetSuffix =false;
  262. vector::iterator iter = m_tagToNodeVec.begin();
  263. for(; iter != m_tagToNodeVec.end(); ++iter)
  264. {
  265. tagSuffixNode* tmp = *iter;
  266. if( strncmp( &(m_cpInternalStr[branch->m_nEdgeLabelEndPos - branch->m_nActiveLen + 2]), &(m_cpInternalStr[tmp->m_nEdgeLabelEndPos - tmp->m_nActiveLen + 1]), branch->m_nActiveLen - 1) == 0)
  267. {
  268. branch->m_tpSuffixLink = tmp;
  269. setSuffix =true;
  270. break;
  271. #ifdef DEBUG
  272. printf("branch[%c] suffix_link is branch[%c]\n", tmp->m_cIndex, branch->m_cIndex);
  273. #endif
  274. }
  275. }
  276. m_tagToNodeVec.push_back(branch);
  277. vector::iterator iter2 = m_tagFromNodeVec.begin();
  278. for(; iter2 != m_tagFromNodeVec.end(); ++iter2)
  279. {
  280. tagSuffixNode* tmp = *iter2;
  281. //找到后缀节点,结束循环
  282. if( strncmp( &(m_cpInternalStr[tmp->m_nEdgeLabelEndPos - tmp->m_nActiveLen + 2]), &(m_cpInternalStr[branch->m_nEdgeLabelEndPos - branch->m_nActiveLen + 1]), tmp->m_nActiveLen - 1) == 0)
  283. {
  284. tmp->m_tpSuffixLink = branch;
  285. m_tagFromNodeVec.erase(iter2);
  286. #ifdef DEBUG
  287. printf("branch[%c] suffix_link is branch[%c]\n", tmp->m_cIndex, branch->m_cIndex);
  288. #endif
  289. break;
  290. }
  291. }
  292. if( !setSuffix )
  293. {
  294. m_tagFromNodeVec.push_back(branch);
  295. }
  296. //已经将新的后缀字符串插入到树中,这时可以结束while了。
  297. break;
  298. }
  299. }
  300. }
  301. //test
  302. #ifdef DEBUG
  303. printf("print\n");
  304. printTree();
  305. #endif
  306. }
  307. }
  308. //查询
  309. intCSuffixTree::search(char*str)
  310. {
  311. if(str == 0)
  312. return-1;
  313. //TODO
  314. //添加处理过程
  315. intlen = strlen(str);
  316. tagSuffixNode* node = 0;
  317. tagSuffixNode* cur = m_tpRoot;
  318. for(inti=0; i
  319. {
  320. node = __findChildBeginWithChar(cur, str[i]);
  321. if(node == 0)
  322. {
  323. break;
  324. }
  325. else
  326. {
  327. intedgeLen = node->m_nEdgeLabelEndPos - node->m_nEdgeLabelStartPos + 1;
  328. intremain = len - i;
  329. if( remain <= edgeLen )
  330. {
  331. if( strncmp(&(str[i]), &(m_cpInternalStr[node->m_nEdgeLabelStartPos]), remain) != 0)
  332. {
  333. return-1;
  334. }
  335. else
  336. {
  337. returnnode->m_nEdgeLabelEndPos - node->m_nActiveLen + 1;
  338. }
  339. }
  340. else
  341. {
  342. if( strncmp(&(str[i]), &(m_cpInternalStr[node->m_nEdgeLabelStartPos]), edgeLen) != 0)
  343. {
  344. return-1;
  345. }
  346. else
  347. {
  348. i += edgeLen;
  349. cur = node;
  350. }
  351. }
  352. }
  353. }
  354. return-1;
  355. }
  356. tagSuffixNode* CSuffixTree::__allocNode()
  357. {
  358. tagSuffixNode* node =newtagSuffixNode;
  359. m_tagNodeList.push_back(node);
  360. node->init();
  361. #ifdef DEBUG
  362. node->m_cIndex = m_cIndex;
  363. m_cIndex++;
  364. #endif
  365. returnnode;
  366. }
  367. tagSuffixNode* CSuffixTree::__findChildBeginWithChar(tagSuffixNode* node,charc)
  368. {
  369. assert(node != 0);
  370. tagSuffixNode* child = node->m_tpChild;
  371. while(child != 0)
  372. {
  373. if( m_cpInternalStr[child->m_nEdgeLabelStartPos] == c)
  374. returnchild;
  375. child = child->m_tpRightSibling;
  376. }
  377. return0;
  378. }
  379. voidCSuffixTree::test()
  380. {
  381. //printf("%s\n", m_cpInternalStr);
  382. printTree();
  383. }
  384. voidCSuffixTree::printTree()
  385. {
  386. #ifdef DEBUG
  387. printf("[A]\n");
  388. #endif
  389. __printHelper(m_tpRoot, 0);
  390. }
  391. voidCSuffixTree::__printHelper(tagSuffixNode* node,intlevel)
  392. {
  393. intstart = node->m_nEdgeLabelStartPos;
  394. intend = node->m_nEdgeLabelEndPos;
  395. tagSuffixNode* child = node->m_tpChild;
  396. if( level > 0 )
  397. {
  398. for(inti=0; i
  399. {
  400. printf(" |");
  401. }
  402. printf(" + ");
  403. for(intj = start; j <= end; j++)
  404. {
  405. printf("%c", m_cpInternalStr[j]);
  406. }
  407. #ifdef DEBUG
  408. printf("[%c]", node->m_cIndex);
  409. //         printf("[%d:%d:%d]", node->m_nEdgeLabelStartPos, node->m_nEdgeLabelEndPos, node->m_nActiveLen);
  410. #endif
  411. printf("\n");
  412. }
  413. while( child != 0 )
  414. {
  415. __printHelper(child, level+1);
  416. child = child->m_tpRightSibling;
  417. }
  418. }
  419. intmain()
  420. {
  421. cout<<"hello suffixtree"<
  422. system("pause");
  423. return0;
  424. }

   

    运行结果如下:1024x551

Shlomo Yona的实现

    下面是国外一牛人Shlomo Yona写的实现(摘取了部分非完整代码):

   

  1. /******************************************************************************
  2. Suffix Tree Version 2.1
  3. AUTHORS
  4. Dotan Tsadok
  5. Instructor: Mr. Shlomo Yona, University of Haifa, Israel. December 2002.
  6. Current maintainer: Shlomo Yona 
  7. COPYRIGHT
  8. Copyright 2002-2003 Shlomo Yona
  9. LICENSE
  10. This library is free software; you can redistribute it and/or modify it
  11. under the same terms as Perl itself.
  12. DESCRIPTION OF THIS FILE:
  13. This is the implementation file suffix_tree.c implementing the header file
  14. suffix_tree.h.
  15. This code is an Open Source implementation of Ukkonen's algorithm for
  16. constructing a suffix tree over a string in time and space complexity
  17. O(length of the string). The code is written under strict ANSI C.
  18. For a complete understanding of the code see Ukkonen's algorithm and the
  19. readme.txt file.
  20. The general pseudo code is:
  21. n = length of the string.
  22. ST_CreateTree:
  23. Calls n times to SPA (Single Phase Algorithm). SPA:
  24. Increase the variable e (virtual end of all leaves).
  25. Calls SEA (Single Extension Algorithm) starting with the first extension that
  26. does not already exist in the tree and ending at the first extension that
  27. already exists. SEA :
  28. Follow suffix link.
  29. Check if current suffix exists in the tree.
  30. If it does not - apply rule 2 and then create a new suffix link.
  31. apply_rule_2:
  32. Create a new leaf and maybe a new internal node as well.
  33. create_node:
  34. Create a new node or a leaf.
  35. For implementation interpretations see Basic Ideas paragraph in the Developement
  36. section of the readme.txt file.
  37. An example of the implementations of a node and its sons using linked lists
  38. instead of arrays:
  39. (1)
  40. |
  41. |
  42. |
  43. (2)--(3)--(4)--(5)
  44. (2) is the only son of (1) (call it the first son). Other sons of (1) are
  45. connected using a linked lists starting from (2) and going to the right. (3) is
  46. the right sibling of (2) (and (2) is the left sibling of (3)), (4) is the right
  47. sibling of (3), etc.
  48. The father field of all (2), (3), (4) and (5) points to (1), but the son field
  49. of (1) points only to (2).
  50. *******************************************************************************/
  51. #include "stdlib.h"
  52. #include "stdio.h"
  53. #include "string.h"
  54. #include "suffix_tree.h"
  55. /* See function body */
  56. voidST_PrintTree(SUFFIX_TREE* tree);
  57. /* See function body */
  58. voidST_PrintFullNode(SUFFIX_TREE* tree, NODE* node);
  59. /* Used in function trace_string for skipping (Ukkonen's Skip Trick). */
  60. typedefenumSKIP_TYPE     {skip, no_skip}                 SKIP_TYPE;
  61. /* Used in function apply_rule_2 - two types of rule 2 - see function for more
  62. details.*/
  63. typedefenumRULE_2_TYPE   {new_son, split}                RULE_2_TYPE;
  64. /* Signals whether last matching position is the last one of the current edge */
  65. typedefenumLAST_POS_TYPE {last_char_in_edge, other_char} LAST_POS_TYPE;
  66. /* Used for statistic measures of speed. */
  67. DBL_WORD counter;
  68. /* Used for statistic measures of space. */
  69. DBL_WORD heap;
  70. /* Used to mark the node that has no suffix link yet. By Ukkonen, it will have
  71. one by the end of the current phase. */
  72. NODE*    suffixless;
  73. typedefstructSUFFIXTREEPATH
  74. {
  75. DBL_WORD   begin;
  76. DBL_WORD   end;
  77. } PATH;
  78. typedefstructSUFFIXTREEPOS
  79. {
  80. NODE*      node;
  81. DBL_WORD   edge_pos;
  82. }POS;
  83. /******************************************************************************/
  84. /*
  85. Define STATISTICS in order to view measures of speed and space while
  86. constructing and searching the suffix tree. Measures will be printed on the
  87. screen.
  88. */
  89. /* #define STATISTICS */
  90. /*
  91. Define DEBUG in order to view debug printouts to the screen while
  92. constructing and searching the suffix tree.
  93. */
  94. /* #define DEBUG */
  95. /******************************************************************************/
  96. /*
  97. create_node :
  98. Creates a node with the given init field-values.
  99. Input : The father of the node, the starting and ending indices
  100. of the incloming edge to that node,
  101. the path starting position of the node.
  102. Output: A pointer to that node.
  103. */
  104. NODE* create_node(NODE* father, DBL_WORD start, DBL_WORD end, DBL_WORD position)
  105. {
  106. /*Allocate a node.*/
  107. NODE* node   = (NODE*)malloc(sizeof(NODE));
  108. if(node == 0)
  109. {
  110. printf("\nOut of memory.\n");
  111. exit(0);
  112. }
  113. #ifdef STATISTICS
  114. heap+=sizeof(NODE);
  115. #endif
  116. /* Initialize node fields. For detailed description of the fields see
  117. suffix_tree.h */
  118. node->sons             = 0;
  119. node->right_sibling    = 0;
  120. node->left_sibling     = 0;
  121. node->suffix_link      = 0;
  122. node->father           = father;
  123. node->path_position    = position;
  124. node->edge_label_start = start;
  125. node->edge_label_end   = end;
  126. returnnode;
  127. }
  128. /******************************************************************************/
  129. /*
  130. find_son :
  131. Finds son of node that starts with a certain character.
  132. Input : the tree, the node to start searching from and the character to be
  133. searched in the sons.
  134. Output: A pointer to the found son, 0 if no such son.
  135. */
  136. NODE* find_son(SUFFIX_TREE* tree, NODE* node,charcharacter)
  137. {
  138. /* Point to the first son. */
  139. node = node->sons;
  140. /* scan all sons (all right siblings of the first son) for their first
  141. character (it has to match the character given as input to this function. */
  142. while(node != 0 && tree->tree_string[node->edge_label_start] != character)
  143. {
  144. #ifdef STATISTICS
  145. counter++;
  146. #endif
  147. node = node->right_sibling;
  148. }
  149. returnnode;
  150. }
  151. /******************************************************************************/
  152. /*
  153. get_node_label_end :
  154. Returns the end index of the incoming edge to that node. This function is
  155. needed because for leaves the end index is not relevant, instead we must look
  156. at the variable "e" (the global virtual end of all leaves). Never refer
  157. directly to a leaf's end-index.
  158. Input : the tree, the node its end index we need.
  159. Output: The end index of that node (meaning the end index of the node's
  160. incoming edge).
  161. */
  162. DBL_WORD get_node_label_end(SUFFIX_TREE* tree, NODE* node)
  163. {
  164. /* If it's a leaf - return e */
  165. if(node->sons == 0)
  166. returntree->e;
  167. /* If it's not a leaf - return its real end */
  168. returnnode->edge_label_end;
  169. }
  170. /******************************************************************************/
  171. /*
  172. get_node_label_length :
  173. Returns the length of the incoming edge to that node. Uses get_node_label_end
  174. (see above).
  175. Input : The tree and the node its length we need.
  176. Output: the length of that node.
  177. */
  178. DBL_WORD get_node_label_length(SUFFIX_TREE* tree, NODE* node)
  179. {
  180. /* Calculate and return the lentgh of the node */
  181. returnget_node_label_end(tree, node) - node->edge_label_start + 1;
  182. }
  183. /******************************************************************************/
  184. /*
  185. is_last_char_in_edge :
  186. Returns 1 if edge_pos is the last position in node's incoming edge.
  187. Input : The tree, the node to be checked and the position in its incoming
  188. edge.
  189. Output: the length of that node.
  190. */
  191. charis_last_char_in_edge(SUFFIX_TREE* tree, NODE* node, DBL_WORD edge_pos)
  192. {
  193. if(edge_pos == get_node_label_length(tree,node)-1)
  194. return1;
  195. return0;
  196. }
  197. /******************************************************************************/
  198. /*
  199. connect_siblings :
  200. Connect right_sib as the right sibling of left_sib and vice versa.
  201. Input : The two nodes to be connected.
  202. Output: None.
  203. */
  204. voidconnect_siblings(NODE* left_sib, NODE* right_sib)
  205. {
  206. /* Connect the right node as the right sibling of the left node */
  207. if(left_sib != 0)
  208. left_sib->right_sibling = right_sib;
  209. /* Connect the left node as the left sibling of the right node */
  210. if(right_sib != 0)
  211. right_sib->left_sibling = left_sib;
  212. }
  213. /******************************************************************************/
  214. /*
  215. apply_extension_rule_2 :
  216. Apply "extension rule 2" in 2 cases:
  217. 1. A new son (leaf 4) is added to a node that already has sons:
  218. (1)        (1)
  219. /   \     ->   / | \
  220. (2)  (3)      (2)(3)(4)
  221. 2. An edge is split and a new leaf (2) and an internal node (3) are added:
  222. |       |
  223. |      (3)
  224. |     ->   / \
  225. (1)       (1) (2)
  226. Input : See parameters.
  227. Output: A pointer to the newly created leaf (new_son case) or internal node
  228. (split case).
  229. */
  230. NODE* apply_extension_rule_2(
  231. /* Node 1 (see drawings) */
  232. NODE*           node,
  233. /* Start index of node 2's incoming edge */
  234. DBL_WORD        edge_label_begin,
  235. /* End index of node 2's incoming edge */
  236. DBL_WORD        edge_label_end,
  237. /* Path start index of node 2 */
  238. DBL_WORD        path_pos,
  239. /* Position in node 1's incoming edge where split is to be
  240. performed */
  241. DBL_WORD        edge_pos,
  242. /* Can be 'new_son' or 'split' */
  243. RULE_2_TYPE     type)
  244. {
  245. NODE *new_leaf,
  246. *new_internal,
  247. *son;
  248. /*-------new_son-------*/
  249. if(type == new_son)
  250. {
  251. #ifdef DEBUG
  252. printf("rule 2: new leaf (%lu,%lu)\n",edge_label_begin,edge_label_end);
  253. #endif
  254. /* Create a new leaf (4) with the characters of the extension */
  255. new_leaf = create_node(node, edge_label_begin , edge_label_end, path_pos);
  256. /* Connect new_leaf (4) as the new son of node (1) */
  257. son = node->sons;
  258. while(son->right_sibling != 0)
  259. son = son->right_sibling;
  260. connect_siblings(son, new_leaf);
  261. /* return (4) */
  262. returnnew_leaf;
  263. }
  264. /*-------split-------*/
  265. #ifdef DEBUG
  266. printf("rule 2: split (%lu,%lu)\n",edge_label_begin,edge_label_end);
  267. #endif
  268. /* Create a new internal node (3) at the split point */
  269. new_internal = create_node(
  270. node->father,
  271. node->edge_label_start,
  272. node->edge_label_start+edge_pos,
  273. node->path_position);
  274. /* Update the node (1) incoming edge starting index (it now starts where node
  275. (3) incoming edge ends) */
  276. node->edge_label_start += edge_pos+1;
  277. /* Create a new leaf (2) with the characters of the extension */
  278. new_leaf = create_node(
  279. new_internal,
  280. edge_label_begin,
  281. edge_label_end,
  282. path_pos);
  283. /* Connect new_internal (3) where node (1) was */
  284. /* Connect (3) with (1)'s left sibling */
  285. connect_siblings(node->left_sibling, new_internal);
  286. /* connect (3) with (1)'s right sibling */
  287. connect_siblings(new_internal, node->right_sibling);
  288. node->left_sibling = 0;
  289. /* Connect (3) with (1)'s father */
  290. if(new_internal->father->sons == node)
  291. new_internal->father->sons = new_internal;
  292. /* Connect new_leaf (2) and node (1) as sons of new_internal (3) */
  293. new_internal->sons = node;
  294. node->father = new_internal;
  295. connect_siblings(node, new_leaf);
  296. /* return (3) */
  297. returnnew_internal;
  298. }
  299. /******************************************************************************/
  300. /*
  301. trace_single_edge :
  302. Traces for a string in a given node's OUTcoming edge. It searches only in the
  303. given edge and not other ones. Search stops when either whole string was
  304. found in the given edge, a part of the string was found but the edge ended
  305. (and the next edge must be searched too - performed by function trace_string)
  306. or one non-matching character was found.
  307. Input : The string to be searched, given in indices of the main string.
  308. Output: (by value) the node where tracing has stopped.
  309. (by reference) the edge position where last match occured, the string
  310. position where last match occured, number of characters found, a flag
  311. for signaling whether search is done, and a flag to signal whether
  312. search stopped at a last character of an edge.
  313. */
  314. NODE* trace_single_edge(
  315. SUFFIX_TREE*    tree,
  316. /* Node to start from */
  317. NODE*           node,
  318. /* String to trace */
  319. PATH            str,
  320. /* Last matching position in edge */
  321. DBL_WORD*       edge_pos,
  322. /* Last matching position in tree source string */
  323. DBL_WORD*       chars_found,
  324. /* Skip or no_skip*/
  325. SKIP_TYPE       type,
  326. /* 1 if search is done, 0 if not */
  327. int*            search_done)
  328. {
  329. NODE*      cont_node;
  330. DBL_WORD   length,str_len;
  331. /* Set default return values */
  332. *search_done = 1;
  333. *edge_pos    = 0;
  334. /* Search for the first character of the string in the outcoming edge of
  335. node */
  336. cont_node = find_son(tree, node, tree->tree_string[str.begin]);
  337. if(cont_node == 0)
  338. {
  339. /* Search is done, string not found */
  340. *edge_pos = get_node_label_length(tree,node)-1;
  341. *chars_found = 0;
  342. returnnode;
  343. }
  344. /* Found first character - prepare for continuing the search */
  345. node    = cont_node;
  346. length  = get_node_label_length(tree,node);
  347. str_len = str.end - str.begin + 1;
  348. /* Compare edge length and string length. */
  349. /* If edge is shorter then the string being searched and skipping is
  350. enabled - skip edge */
  351. if(type == skip)
  352. {
  353. if(length <= str_len)
  354. {
  355. (*chars_found)   = length;
  356. (*edge_pos)      = length-1;
  357. if(length < str_len)
  358. *search_done  = 0;
  359. }
  360. else
  361. {
  362. (*chars_found)   = str_len;
  363. (*edge_pos)      = str_len-1;
  364. }
  365. #ifdef STATISTICS
  366. counter++;
  367. #endif
  368. returnnode;
  369. }
  370. else
  371. {
  372. /* Find minimum out of edge length and string length, and scan it */
  373. if(str_len < length)
  374. length = str_len;
  375. for(*edge_pos=1, *chars_found=1; *edge_pos
  376. {
  377. #ifdef STATISTICS
  378. counter++;
  379. #endif
  380. /* Compare current characters of the string and the edge. If equal -
  381. continue */
  382. if(tree->tree_string[node->edge_label_start+*edge_pos] != tree->tree_string[str.begin+*edge_pos])
  383. {
  384. (*edge_pos)--;
  385. returnnode;
  386. }
  387. }
  388. }
  389. /* The loop has advanced *edge_pos one too much */
  390. (*edge_pos)--;
  391. if((*chars_found) < str_len)
  392. /* Search is not done yet */
  393. *search_done = 0;
  394. returnnode;
  395. }
  396. /******************************************************************************/
  397. /*
  398. trace_string :
  399. Traces for a string in the tree. This function is used in construction
  400. process only, and not for after-construction search of substrings. It is
  401. tailored to enable skipping (when we know a suffix is in the tree (when
  402. following a suffix link) we can avoid comparing all symbols of the edge by
  403. skipping its length immediately and thus save atomic operations - see
  404. Ukkonen's algorithm, skip trick).
  405. This function, in contradiction to the function trace_single_edge, 'sees' the
  406. whole picture, meaning it searches a string in the whole tree and not just in
  407. a specific edge.
  408. Input : The string, given in indice of the main string.
  409. Output: (by value) the node where tracing has stopped.
  410. (by reference) the edge position where last match occured, the string
  411. position where last match occured, number of characters found, a flag
  412. for signaling whether search is done.
  413. */
  414. NODE* trace_string(
  415. SUFFIX_TREE*    tree,
  416. /* Node to start from */
  417. NODE*           node,
  418. /* String to trace */
  419. PATH            str,
  420. /* Last matching position in edge */
  421. DBL_WORD*       edge_pos,
  422. /* Last matching position in tree string */
  423. DBL_WORD*       chars_found,
  424. /* skip or not */
  425. SKIP_TYPE       type)
  426. {
  427. /* This variable will be 1 when search is done.
  428. It is a return value from function trace_single_edge */
  429. intsearch_done = 0;
  430. /* This variable will hold the number of matching characters found in the
  431. current edge. It is a return value from function trace_single_edge */
  432. DBL_WORD edge_chars_found;
  433. *chars_found = 0;
  434. while(search_done == 0)
  435. {
  436. *edge_pos        = 0;
  437. edge_chars_found = 0;
  438. node = trace_single_edge(tree, node, str, edge_pos, &edge_chars_found, type, &search_done);
  439. str.begin       += edge_chars_found;
  440. *chars_found    += edge_chars_found;
  441. }
  442. returnnode;
  443. }
  444. /******************************************************************************/
  445. /*
  446. ST_FindSubstring :
  447. See suffix_tree.h for description.
  448. */
  449. DBL_WORD ST_FindSubstring(
  450. /* The suffix array */
  451. SUFFIX_TREE*    tree,
  452. /* The substring to find */
  453. char*  W,
  454. /* The length of W */
  455. DBL_WORD        P)
  456. {
  457. /* Starts with the root's son that has the first character of W as its
  458. incoming edge first character */
  459. NODE* node   = find_son(tree, tree->root, W[0]);
  460. DBL_WORD k,j = 0, node_label_en

数据分析咨询请扫描二维码

客服在线
立即咨询