IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆和并查集 -> 正文阅读

[数据结构与算法]堆和并查集

堆(STL中的优先队列)

优先队列:在队列中,元素被赋予优先级,优先级最高的最先被弹出

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

int main()
{
    //STL中的优先队列默认以大为优先级
    priority_queue<int> q1;
    q1.push();//push a element into the queue
    q1.top();//botain the top element
    q1.empty();//the queue is empty?
    q1.size();//inquire the queue size
    q1.pop();//delete the top element in queue
    
    //下面这个是小顶堆,以小为优先级
    priority_queue<int, vector<int>, greater<int> > q2;
}

学习堆

在学习堆之前,我们要知道什么叫完全二叉树

二叉树:指树种的节点的度不大于2的有序树

  • 结点的度:一个节点拥有子树的数目 成为 结点的度

  • 节点名称:左子节点,右子节点,父节点

  • 结点层次:根节点为1,根节点的子节点为2,以此类推

  • 树的深度:树的高度,也是层次的最大值

?

完全二叉树:深度为k,有n个结点的二叉树,当且仅当每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树,如图所示

通俗来讲,除了最深层,其他所有层数的结点都是满的,最深层的结点从左到右,编号递增排列

?

?

实现完全二叉树

用数组实现

注意下标从1开始

// 设当前结点编号为i,其左子节点编号为lson,其右子节点编号为rson,其父节点编号为fa
int lson = i << 1;
int rsom = i << 1 | 1;
int fa = i >> 1;

//根节点是没有父节点的

模拟堆

构建一个小根堆

//1读入
int n;
for(int i = 1; i <= n; i++)
	cin >> h[i];
len = n;

for(int i = n/2; i; i--)	down(i);

//2插入
Insert(x);

插入

  • Insert

void Insert(int x)
{
	len ++;
	h[len] = x;
	up(len);
}
  • down

void down(int index)
{
	int t = index;
	int lson = t << 1, rson = t << 1 | 1;
	if(lson <= len && h[lson] < h[t])	t = lson;
	if(rson <= len && h[rson] < h[t])	t = rson;
	
	if(t != index)
	{
		swap(h[t], h[index]);
		down(t);
	}
}
  • up

void up(int index)
{
	if(index >> 1 > 0 && h[index] < h[index >> 1])
	{
		swap(h[index], h[index >> 1]);
		up(index >> 1);
	}
}

删除

//删除头部
void pop_top()
{
	h[1] = h[len];
	len--;
	down(1);
}

//删除任意
void Delete(int index)
{
	h[index] = h[len];
	len--;
	down(index);
	up(index);
}

给出一道题 可以自行联系模拟堆的部分操作

AcWing 838. 堆排序 - AcWing

在实际做题中,很少使用手写堆,而是使用STL中的priority_queue

----------------------------------------------------------------------------------

并查集

现在有一个问题:给出n个点和m条边的无向图,询问任意两点是否连通

我们能想到的比较朴素的算法就是dfs搜索 看一下能不能搜到,时间复杂度是o(n)

引入并查集

并查集可以在将近o(1)的情况下来查询两个点是否处于一个集合中

应用

  • 合并:把两个不相交的集合合并为一个

  • 查询:查询两个集合是否在同一集合中

我们可以这样想象

一开始有n个人,这n个人一开始只有一个老大,就是自己

?

在争夺地盘的时候,逐渐形成了帮派

有的人开始认老大,有的人收小弟

?有的老大在抢地盘的时候败北,带着自己的小弟全部投靠了那位老大

?

这里需要非常注意的是:

  • 只能是一个老大带领小弟并入别的帮派,因为只有老大才能代表着一个帮派的行为

  • 如上图,6号结点的顶头上司还是4号结点,只是6号结点的最终老大是1号。因此在查询的时候就得一层一层地往上询问老大是谁

简述一下代码思路

利用树来存储每一个集合,用树根(老大)的编号来代表整个集合的编号。每个节点存储他的父节点,例如p[x]就是x的父节点。

问题1:如何判断树根?

答;自己的老大是自己的人,就是树根,也就是根节点

If(fa[x] == x)

问题2:如何求x的集合编号?

答:通俗的说,从x一路向上直到树根。

while(fa[x] != x)	x = fa[x];

问题三:如何查询x和y是否在一个集合里?

答:fa[x] == fa[y] 代表x和y在同一个集合

问题四:如何合并两个集合?

答:加一条边(一个集合的根节点的父节点为另一个集合的根节点)

fa[x] = y;

我们讨论一种极端情况

在上面的问题2中,出现了这样的情况

  • 一个帮派非常非常多人

  • 帮派的人所形成的关系是一种线性的,那么他的查询时间将会是o(n),反复查询的话时间复杂度太大,没有达到预想中的效果

根据上述情况,我们提出了名叫路径压缩的方法

在每次查询的时候,把路径上的点的父亲改成根节点,以便于以后再查询

模板如下

void find(int x)
{
	if(fa[x] != x)	fa[x] = find(fa[x]);
	return fa[x];
}

并查集裸题

AcWing 836. 合并集合 - AcWing

这里有并查集的基本使用方法

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-17 11:44:21  更:2022-01-17 11:46:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 19:31:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码