堆 \color{red}{\huge{堆}} 堆
堆是一种可以 快速查找一个数据集合中最大值和最小值的数据结构 \color{purple}{快速查找一个数据集合中最大值和最小值的数据结构} 快速查找一个数据集合中最大值和最小值的数据结构。并且当新进入或者新去除元素之后可以 自行调整内部元素从而完成自动更新最值。 \color{purple}{自行调整内部元素从而完成自动更新最值。} 自行调整内部元素从而完成自动更新最值。
①.堆的表现形式
- 堆其实是由 完全二叉树 \color{blue}{完全二叉树} 完全二叉树所建造成的,在该完全二叉树中满足所有父节点都小于(大于)它对应的孩子节点。
这就是堆的逻辑存储方式,依托于二叉树。因为这些性质也就决定了,堆的最值都是在祖宗节点处体现。
-
一维数组存储堆
\color{olive}{\huge{一维数组存储堆}}
一维数组存储堆
就像一维数组存储完全二叉树一样去存储堆即可。
需要注意的是, 堆在数组中存储下标一定要从 1 开始存储 \color{red}{堆在数组中存储下标一定要从1开始存储} 堆在数组中存储下标一定要从1开始存储,从 0 0 0开始会有很麻烦的边界检验问题。
-
堆数据更新
(
默认小顶堆
)
\color{olive}{\huge{堆数据更新(默认小顶堆)}}
堆数据更新(默认小顶堆)
d o w n 操作: down操作: down操作:如果一个数据比它下面位置的数据要大,那么它应该“下沉”。这时需要 d o w n down down操作来调换元素位置。
u p 操作: up操作: up操作:如果一个数据比它上面的数据要小,那么它应该“上浮”。这时需要 u p up up操作来调换元素位置。
d o w n down down和 u p up up操作进行数据调整的时候, 一定是在父节点、左右孩子节点中最值进行交换 \color{red}{一定是在父节点、左右孩子节点中最值进行交换} 一定是在父节点、左右孩子节点中最值进行交换,这样才能保证交换完之后堆结构仍然不被破坏。
②. 堆具体操作
首先是两个最为基础的操作。
d
o
w
n
操作
\color{blue}{\huge{down操作}}
down操作
K
e
y
:
Key:
Key:从三个节点之中选择最小的值,交换到父节点即可。
void down(int u)
{
int t = u;
if(u * 2 <= cnt && h[u * 2] < h[t])
t = u * 2;
if(u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t])
t = u * 2 + 1;
if(u != t)
{
swap(h[u],h[t]);
down(t);
}
}
u
p
操作
\color{blue}{\huge{up操作}}
up操作
K
e
y
:
Key:
Key:每次和对应的父节点交换即可。
void up(int u)
{
while(u / 2 && h[u / 2] > h[u])
{
swap(h[u / 2] , h[u]);
u /= 2;
}
return ;
}
1.
插入一个数
\color{red}{\huge{插入一个数}}
插入一个数
堆中插入数据的时候,就是在堆尾插入数据,之后进行
u
p
up
up操作,如果能
u
p
up
up就
u
p
up
up,不能
u
p
up
up说明它现在插入的位置就是刚好在的位置。
heap[++size] = x; //堆尾插入元素
up(size); //将size对应的元素进行up操作调整位置
2.
取出当前集合中元素最小值
\color{red}{\huge{取出当前集合中元素最小值}}
取出当前集合中元素最小值
根据堆的性质就可以直接从堆顶得出。
heap[1];
3.
删除最小值
\color{red}{\huge{删除最小值}}
删除最小值
堆的物理存储是依托于一维数组,所以在数组头部进行删除操作太过于麻烦。可以先将尾部元素与头部元素进行交换,然后直接删除尾部的元素,最后对头部元素进行
d
o
w
n
down
down操作就可以了。
heap[1] = heap[size];
size--;
down(1);
4.
删除任意一个元素
\color{red}{\huge{删除任意一个元素}}
删除任意一个元素
仿照
3
3
3操作即可
heap[k] = heap[size];
size--;
down(k); //反正down和up都只能满足一个
up(k); //索性全部搞一次
5.
修改任意一个元素
\color{red}{\huge{修改任意一个元素}}
修改任意一个元素
修改值之后,利用
d
o
w
n
down
down和
u
p
up
up调整元素即可、
heap[k] = x;
down(k);
up(k);
③. 完整代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,m;
int h[N],cnt;
void down(int u)
{
int t = u;
if(u * 2 <= cnt && h[u * 2] < h[t])
t = u * 2;
if(u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t])
t = u * 2 + 1;
if(u != t)
{
swap(h[u],h[t]);
down(t);
}
return ;
}
void up(int u)
{
while(u / 2 && h[u / 2] > h[u])
{
swap(h[u / 2],h[u]);
u /= 2;
}
return ;
}
int main ()
{
cin >> n >> m;
for(int i = 1 ; i <= n ; i++)
{
cin >> h[i];
}
cnt = n;
for(int i = n / 2 ; i ; i--)
{
down(i);
}
while(m--)
{
cout << h[1] << " ";
h[1] = h[cnt--];
down(1);
}
puts("");
return 0;
}