数据结构2

目录

前言

一、什么是Trie树?

二.Tire树的操作

2.1插入

2.2 查询

三.总结

二.并查集

1.概述

2.find(x)函数的实现 (路径压缩法)

前言

本文包含几种数据结构,分别为Trie树,并查集,堆,哈希表

一、什么是Trie树?

Trie树,也叫字典树,是高效的存储和查找字符串集合的数据结构。Trie树的本质是利用字符串的公共前缀,将重复的前缀合并在一起,从而提高查找的效率。

Trie树的三种性质:

1.Trie树的根结点没有值,除了根结点外每一个结点都包含一个字符

2.从根结点到对应某一个结点的路径连起来就是所对应的存储的字符串(如果对应字符串结尾存在)

3.每个结点所对应的子结点不同

二.Tire树的操作

2.1插入

如图所示,就是一个以 26个字母为例的Trie树,如果我们要插入字符串abcdef,那么我们从根节点往下看,没有a那么我们插入a,以此类推一直插入到f,形成如图a到f的一条路径,要注意的是我们在插入结束之后要在f打上一个标记来说明存入的是abcdef,因为如果查找的时候abcd也同样是a到f的一条路径,但是这个字符串我们并没有存下来。

代码

#include <iostream>
using namespace std;
const int N=1e6+10;
int son[N][26];//以存储26个字母为例,son数组存储子结点
int cnt[N],idx;//cnt数组存储以有多少i为下标的字符结尾的字符串个数
//idx为当前用到的结点

void insert(char str[]){
	int p=0;//从根结点往下创建
	for(int i=0;str[i];i++){
		int u=str[i]-'a';
		if(!son[p][u]) son[p][u]=++idx;//如果不存在这个点就创建
		p=son[p][u];//往下走 
	} 
	cnt[p]++;//走完之后将最后一个纪录 
} 

写代码的时候发现第一次插入查询总是会是0,仔细检查才发现在插入的时候要++idx而不是idx++,因为idx刚刚开始是0,也就是说把0给了第一个插入的字符串,那么就没有插入成功orz

2.2 查询

查询操作和插入操作几乎是一样的思路,就是如果子节点存在那么就继续往下,知道查找字符串结束,如果不存在返回0

代码:

void insert(char str[]){
	int p=0;//从根结点往下创建
	for(int i=0;str[i];i++){
		int u=str[i]-'a';
		if(!son[p][u]) son[p][u]=++idx;//如果不存在这个点就创建
		p=son[p][u];//往下走 
	} 
	cnt[p]++;//走完之后将最后一个纪录 
} 

三.总结

Tire树作为一种存储的数据结构,其实是用空间换时间的方式,插入和查询操作的时间复杂度都是o(n)的

二.并查集

1.概述

并查集作为一种树状的数据结构,一般用于处理不相交的集合问题,顾名思义,也就是实现并和查的用途x(说了和没说一样),我们可以用并查集判断一个森林中有几棵树,某个节点是否属于某颗树

并查集主要由一个数组p[N],和操作find(x)组成,其中数组p是用来维护一个集合的,我们让p[x]表示x的父亲结点。树根的编号就是集合的编号

如何判断一个节点是否是树根:if(p[x]==x)

如何求x属于哪个集合:while(p[x]!=x) x=p[x]

如何合并两个集合:若px是x集合的编号,py是y集合的编号只要让p[x]=y

2.find(x)函数的实现 (路径压缩法)

假设我们不使用 路径压缩,那么我们需要定义一个数组p[],这个数组p维护一个集合,若p[10]=6就说明10号节点的父结点为6,如果一个结点的父结点是自己本身,那么他就是代表集合的根节点。我们的find(x)目的就是找到x的根结点

非路径压缩实现find(x)函数:

int find(int x)//需要查找的元素
{
    while(p[x]!=x){
        x=p[x];
    }
return x;
}

在说路径压缩法之前,我们先提一个函数,他的作用是为了合并两个集合,也就是给出分别属于两个不同集合的元素x,y,把他们所属的集合合并。设我们的合并函数为add(int x,int y)add函数具体实现逻辑如下:

1.用find函数寻找x的根节点

2.用find函数寻找y的根节点

3.把x(y)的根节点作为y(x)的父亲节点

代码:

void add(int x,int y){
	int fx=find(x);
	int fy=find(y);//找到两者的根节点
	if(fx!=fy) p[fx]=fy;//判断两者是否是同一个集合,如果不是就合并 
	 
} 

通常情况下,我们可以通过find函数和add函数实现多个集合的并查操作,但是有一个问题是没有指定明确谁是前驱的过程,所以在合并中可能会出现单支树的情况,这时候查找就受到树的高度的限制!

所以我们就产生路径压缩的方法:

  当从某个节点出发去寻找它的根节点时,我们会途径一系列的节点,在这些节点中,除了根节点外,其余所有节点,都需要更改直接前驱为根节点
因此,基于这样的思路,我们可以通过递归的方法来逐层修改返回时的某个节点的直接前驱(即p[x]的值)。简单说来就是将x到根节点路径上的所有点的pre(上级)都设为根节点。下面给出具体的实现代码:

int find(int x)
{
	if(p[x]=x) return x;//递归出口如果x就是集合的根节点返回
	return p[x]=find(p[x]);	
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值