题解 P3370 【【模板】字符串哈希】
其实这题不用哈希,用二叉搜索树就可以解决了
什么是二叉搜索树
- 每个元素都有一个关键字,并且任意两个关键字都不同;因此,所有的关键字都是唯一的。
- 在根节点的左子树中,元素的关键字(如果有的话)都小于根节点的关键字。
- 在根节点的右子树中,元素的关键字(如果有的话)都大于根节点的关键字。
- 根节点的左子树,右子树也是二叉搜索树
如图:这两棵树都是二叉搜索树
由此看出:二叉搜索树的时间复杂度为O(h) ,h为树的高度。也就是说二叉搜索树的平均时间为O(log n),最坏为O(n)。随机数据的情况下最坏的几率很小。
依题意,我们只要把关键字 key由数字改为字符串即可。
插入
要插入 D ,因为树为空,所以直接插入到根节点,插入成功。
然后要插入 A, 因为D的字典序比A大,指针指向D的左子树,发现D的左子树为空,所以插入到D的左子树,插入成功,如下图所示。
然后要插入 F, 因为D的字典序比F小,指针指向D的右子树,发现D的右子树为空,所以插入到D的左子树,插入成功,如下图所示。
然后要插入 E,因为D的字典序比E小,指针指向D的右子树(也就是指针指向F),之后发现 E的字典序比 F小,指针指向 F的左子树,发现左子树为空,所以插入到F的左子树,插入成功,如下图所示。
最后要插入 A,因为D的字典序比A大,指针指向D的左子树,注意的地方来了 ,发现 A已经存在了,所以插入失败。
以此类推,我们这要统计 插入成功 的次数,把他输出即可。
然后我们可以很容易用链表写出二叉搜索树来。
#include <iostream>
#include<cstdio>
#include<string>
template<typename A, typename B>
class Binary_Search_Tree
{
public:
Binary_Search_Tree()
{
root = NULL;
treesize = 0;
}
~Binary_Search_Tree()
{
}
/*插入元素*/
void ins(const A thekey, const B thedate)
{
node *q = root, *qq = NULL;
while (q != NULL)
{
qq = q;
if (thekey > q->key)/*如果要查找的关键字大于根节点的关键字,则取右子树找*/
q = q->right;
else if (thekey < q->key)/*如果要查找的关键字小于根节点的关键字,则取左子树找*/
q = q->left;
else
{
q->date = thedate; /*如果相同关键字,则覆盖旧的值*/
return;
}
}
/*新建节点*/
node *newnode = new node(thekey, thedate);
if (root != NULL) /*如果树不为空*/
{
if (thekey > qq->key)
qq->right = newnode;
else qq->left = newnode;
}
else /*如果树为空*/
root = newnode;
treesize++;
}
/*返回节点个数*/
inline unsigned int size()const
{
return treesize;
}
private:
struct node
{
A key;
B date;
node *left, *right;
node(A _key,B _date)
{
key = _key;
date = _date;
left = NULL;
right = NULL;
}
}*root;
unsigned int treesize;
};
Binary_Search_Tree<std::string, bool> t;
int main()
{
int n;
scanf("%d", &n);
std::string tmp;
for (int i = 1; i <= n; i++)
{
std::cin >> tmp;
t.ins(tmp, 1);
}
printf("%d", t.size());
return 0;
}
二叉搜索树还有很多功能(查找、删除、最小值、最大值and so on),但是对于本题我们就不需要了,如果想学习的自行百度。如果你对二叉搜索树感兴趣的话,请学习特殊的平衡二叉搜索树:AVL树,它能保证树的高度为log(n),也就是查找,插入,删除的复杂度都为log(n)。
如果还有不懂的可以点我头像私信我,如果你发现本题解有问题或有写得不清楚的地方,欢迎私信或在评论区留言。