码迷,mamicode.com
首页 > 编程语言 > 详细

自己写的一个后缀树算法查找一个字符串的最长重复子串

时间:2016-07-12 00:14:27      阅读:450      评论:0      收藏:0      [点我收藏+]

标签:源代码   public   字符串   博客   程序   后缀树   

    在上个星期面试一家公司的笔试题上面的最后一道题就是写程序查找一个字符串的最长重复子串。当时想了很长时间没想出什么好方法,就把一个算法复杂度比较高的算法写上去了。回来上机把那个算法写了一遍测试没问题,然后自己又到网上面查查还有什么方法,然后发现好像有种叫做后缀树的方法,然后看那个方法,当时没给出代码,看图看了老半天加之自己想了好几个小时终于知道后缀树是个什么东西。然后自己萌生了一个自己写一个后缀树算法解决那个重复子串的问题。然后写了一天终于写出来了。后续有做了一些测试,发现自己写的一个只有几十个字母的字符串比之前的那个算法慢了好几十倍,想了很久想不出原因,后来自己随机生成了一个10000个字符的字符串使用后缀树算法比旧的方法快了4倍,所以后缀树算法还是一个比较优秀的算法的。但是为了以后能够回来看下自己写的东西,所以就写这篇博客记录一下自己写的后缀树算法的源代码。一下是代码

class SuffixTreeNode;
typedef SuffixTreeNode* SuffixTreeNodePtr;

class SuffixTreeNode {
public:
	SuffixTreeNode();
	void initNode();
	SuffixTreeNodePtr& returnChildsAt(int i);
	int cmpSameLength(const char *start);
	void setHead(const char *start);
	const char* getHead();
	void setLen(int length);
	int getLen();
	void setStartPos(int pos);
	int getStartPos();
private:
	const char *pHead;
	int len;
	int start;
	SuffixTreeNode* childs[256];
};


class SuffixTree {
public:
	SuffixTree();
	~SuffixTree();
	int insert(const char *start, int pos);
private:
	SuffixTreeNode* allocNode();
	bool allocBufferNode(int size = 1024);
	int innerInsert(SuffixTreeNode *pNode, const char *start, int pos, int preSameLength);


	SuffixTreeNode* root;
	SuffixTreeNode* freeNode;
	int maxStrLen;
	std::vector<SuffixTreeNode*> nodeBuff;
};


SuffixTreeNode::SuffixTreeNode() {
	initNode();
}

void SuffixTreeNode::initNode() {
	memset(this, 0, sizeof(SuffixTreeNode));
}

SuffixTreeNodePtr& SuffixTreeNode::returnChildsAt(int i) {
	return childs[i];
}

int SuffixTreeNode::cmpSameLength(const char *start) {
	int length = 0;
	if (pHead != NULL)
		for (; (length < len) && (pHead[length] == start[length]); length++);
	else
		return 0;
	return length;
}

void SuffixTreeNode::setHead(const char *start) {
	pHead = start;
}

const char* SuffixTreeNode::getHead() {
	return pHead;
}

void SuffixTreeNode::setLen(int length) {
	len = length;
}

int SuffixTreeNode::getLen() {
	return len;
}

void SuffixTreeNode::setStartPos(int pos) {
	start = pos;
}

int SuffixTreeNode::getStartPos() {
	return start;
}

SuffixTree::SuffixTree() : root(NULL), freeNode(NULL){
}

SuffixTree::~SuffixTree() {
	for (size_t i = 0; i < nodeBuff.size(); i++) {
		SuffixTreeNode* pNode = nodeBuff.at(i);
		if (pNode != NULL) {
			free(pNode);
		}
	}
}

bool SuffixTree::allocBufferNode(int size) {
	SuffixTreeNode *pNode = (SuffixTreeNode*)malloc(sizeof(SuffixTreeNode) * size);

	if (pNode == NULL) {
		return false;
	}

	nodeBuff.push_back(pNode);

	for (int i = 0; i < size; i++) {
		pNode->returnChildsAt(0) = freeNode;
		freeNode = pNode;
		pNode++;
	}

	return true;
}

SuffixTreeNode* SuffixTree::allocNode() {
	if (freeNode == NULL) {
		if (!allocBufferNode())
			return NULL;
	}

	assert(freeNode != NULL);

	SuffixTreeNode* pNode = freeNode;
	freeNode = freeNode->returnChildsAt(0);

	return pNode;
}

int SuffixTree::insert(const char *start, int pos) {
	if (root == NULL) {
		root = allocNode();
		if (root == NULL) {
			return 0;
		}

		root->initNode();

		maxStrLen = strlen(start);

	}

	return innerInsert(root, start, pos, 0);
}

int SuffixTree::innerInsert(SuffixTreeNode *pNode, const char *start, int pos, int preSameLength) {
	if (pNode == NULL)
		return 0;
	int sameLength = pNode->cmpSameLength(start);
	if (sameLength < pNode->getLen()) {
		SuffixTreeNode *pRetNode = allocNode();
		if (pRetNode == NULL) {
			return 0;
		}

		pRetNode->initNode();
		pRetNode->setHead(pNode->getHead() + sameLength);
		pRetNode->setLen(pNode->getLen() - sameLength);
		pRetNode->setStartPos(pNode->getStartPos());
		pNode->setLen(sameLength);
		for (int i = 0; pNode->returnChildsAt(i) != NULL; i++) {
			pRetNode->returnChildsAt(i) = pNode->returnChildsAt(i);
			pNode->returnChildsAt(i) = NULL;
		}
		pNode->returnChildsAt(0) = pRetNode;

		pRetNode = allocNode();
		if (pRetNode == NULL) {
			return 0;
		}

		pRetNode->initNode();
		pRetNode->setHead(start + sameLength);
		pRetNode->setLen(maxStrLen - (pos + preSameLength + sameLength));
		pRetNode->setStartPos(pos);
		pNode->returnChildsAt(1) = pRetNode;
	}
	else if (sameLength == pNode->getLen()) {
		int index = 0;
		for (;pNode->returnChildsAt(index) != NULL; index++) {
			if ((pNode->returnChildsAt(index)->getHead())[0] == start[sameLength]) {
				return sameLength + innerInsert(pNode->returnChildsAt(index), start + sameLength, pos, preSameLength + sameLength);
			}
		}
		SuffixTreeNode *pRetNode = allocNode();
		if (pRetNode == NULL) {
			return 0;
		}

		pRetNode->initNode();
		pRetNode->setHead(start + sameLength);
		pRetNode->setLen(maxStrLen - (pos + preSameLength + sameLength));
		pRetNode->setStartPos(pos);
		pNode->returnChildsAt(index) = pRetNode;
	}

	return sameLength;
}

string findMax(string &ret) {
	int maxLen = 0;
	int maxPos = 0;
	SuffixTree tree;
	const char *str = ret.c_str();
	for (int i = 0; str[i] != ‘\0‘; i++) {
		int curLen = tree.insert(str + i, i);
		if (curLen > maxLen) {
			maxLen = curLen;
			maxPos = i;
		}
	}

	return ret.substr(maxPos, maxLen);
}

findMax函数就是那个找到最长重复子串那个函数了。

自己写的一个后缀树算法查找一个字符串的最长重复子串

标签:源代码   public   字符串   博客   程序   后缀树   

原文地址:http://7044041.blog.51cto.com/7034041/1825520

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!