HUD 5687(字典树)

反思:之前在删除单词的时候,只是删除掉单词前缀以后的字符,而没有把整个单词都删除掉,导致WA了很多次。

高手请略过...

AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;

struct Dic {
	Dic *nt[26];//指向下一个字符的指针
	int num;//重叠字符出现的个数
	Dic() {
		num = 1;//明显,初始化的时候,字符就为1个
		for (int i = 0; i < 26; i++)nt[i] = NULL;
	}
};

void insert(Dic *root, char *str) {
	int len = strlen(str);
	int pos;
	Dic *p = root;

	for (int i = 0; i < len; i++) {
		pos = str[i] - 'a';
		if (p->nt[pos] == NULL) p->nt[pos] = new Dic;//字典中不存在这个字符,则插入一个新的结点
		else p->nt[pos]->num++;//如果该字符存在,则该结点的重叠个数+1
		p = p->nt[pos];
	}
}

bool search(Dic *root, char *str) {
	int len = strlen(str);
	int pos;
	Dic *p = root;

	for (int i = 0; i < len; i++) {
		pos = str[i] - 'a';
		if (p->nt[pos] == NULL)return false;
		p = p->nt[pos];
	}
	return true;
}

void Del(Dic *root, char *str) {
	Dic *pre = NULL, *p = root;
	int len = strlen(str);
	int pos, sum;

	//遍历到前缀的最后一个字符
	for (int i = 0; i < len; i++) {
		pos = str[i] - 'a';
		if (p->nt[pos] == NULL)return;
		p = p->nt[pos];
	}
	sum = p->num;//拥有这个前缀的单词的个数
	p = root;

	for (int i = 0; i < len; i++) {
		pos = str[i] - 'a';
		pre = p;//记录前一个结点,方便删除
		p = p->nt[pos];
		p->num -= sum; //因为要删除“拥有这个前缀单词”,所以就需要在树上减去 “拥有这个前缀的单词的个数”
		if (p->num == 0) //如果为0,则表明:拥有这个前缀的单词都不存在了,所以直接赋值为NULL
			pre->nt[pos] = NULL;
	}
}

int main() {
	int N;
	Dic *root = new Dic;
	cin >> N;
	while (N--) {
		char order[10], str[31];
		scanf("%s %s", order, str);

		if (order[0]=='i') {
			insert(root, str);
		}
		else if (order[0] == 'd') {
			Del(root, str);
		}
		else if (order[0] == 's') {
			if (search(root, str)) printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq742762377/article/details/85462732
HUD