递归实现双数组字典树AC⾃动机

递归实现双数组字典树AC⾃动机

普通AC⾃动机的递归实现过程

void build_ac(Node *node) {
/* 根节点的⽗亲 == NULL */
	if (node == NULL) return ;//递归出⼝:当node为空,返回.
/* 因为该递归思想是深度优先搜索进⾏ac⾃动机的创建,且ac⾃
动机的失败指针在建⽴的过程中必须得先将⽗亲节点的失败指针确
定好后才可建⽴孩⼦节点的失败指针,所以如果当前节点的失败指
针为空时,向上返回到其的⽗亲节点,看看该⽗亲节点的失败指针
是否创建完毕,若没建⽴完毕,向上返回到⽗亲节点的⽗亲节点
(该过程向上递归) */
	if (node->fail == NULL) {
	build_ac(node->father);
}
	for (int i = 0; i < BASE; i++) {
		//该⾏确定当前⼦节点的失败指针
		if (node->next[i] == NULL) continue;
		/*若他的孩⼦ = NULL,跳过*/
		if (node->next[i]->fail) continue;
        /* 若他的孩⼦有失败指针,跳过。跳过是为了避免失
        败指针的重复建⽴ */
		Node *p = node->fail;/*p节点有可能等于根节
		点,所以最上⾯的root有可能== NULL*/
		Node *pre_p = node;//⽤来保存上⼀次的值
		while (p && p->next[i] == NULL) {
			/* 如果node的失败指针没有失败指针则向上递归
			到该节点的⽗亲节点,过程同上,向上递归最后的
			结果是node的失败指针所在的整条⽀路的节点的
			失败指针都建⽴完毕 */
			if (p->fail == NULL) build_ac(p->father);
			/* 否则跳到失败指针所指的节点 */
			p = p->fail;
		}
		if (p == NULL) p = pre_p;/*若失败指针指向
		空,则将上⼀次node赋值给p*/
		else p = p->next[i];/*表⽰在p的孩⼦节点中找
		到了想要找的节点,将p的孩⼦节点赋值给p*/
		node->next[i]->fail = p;/*所以node孩⼦的失
		败指针为新的p节点*/
		build_ac(node->next[i]);//继续递归node的孩⼦节点
	}
}

双数组字典数的递归建⽴过程

/* 该函数是⽤来确定now的孩⼦是否真的是它⾃⼰的孩⼦ */
int has_child(DATNode *trie, int now, int i) {
	return abs(trie[trie[now].base + i].check) == now;
}
void build_ac(DATNode *trie, int now) {
	if (!trie[now].check) return ;/*如果now的check
	值为0,表⽰他没有⽗亲节点,即节点本⾝ == NULL,返回*/
	if (!trie[now].fail) build_ac(trie, abs(trie[now].check));
	/*向上递归返回⽗节点的过程同上*/
	for (int i = 0; i < BASE; i++) {
		if (trie[now].base + i == 0) continue;
        /* 若他的孩⼦不是他⾃⼰的,跳过。因为会出现他的
        孩⼦的check值存的不是他⾃⼰的情况 */
		if (!has_child(trie, now, i)) continue;
		if (trie[trie[now].base + i].fail) continue;
		int p = trie[now].fail;
		/*看now失败指针的孩⼦中有没有这个孩⼦,没有就跳
		到失败指针的失败指针上继续找*/
		while (p && !has_child(trie, p, i)) {
			if (p->fail == NULL) build_ac(p->father);	
			p = trie[p].fail;
		}
		if (p == 0) p = 1;/*p = 0代表失败指针为空,1
		代表根的base值,当now的失败指针为空时,now的失	
		败指针指向根节点*/
		else p = trie[p].base + i;/*now孩⼦的失败指
		针就是p的孩⼦之⼀*/
		trie[trie[now].base + i].fail = p;
		/*所以now的孩⼦的失败指针指向刚找到的节点*/
		build_ac(trie, trie[now].base + i);
		/*递归建⽴孩⼦节点的失败指针*/
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值