【模板】堆 (C++)

题目描述

给定一个数列,初始为空,请支持下面三种操作:

1. 给定一个整数x,请将x加入到数列中。
2. 输出数列中最小的数。
3. 删除数列中最小的数(如果有多个数最小,只删除1个)。

输入格式

第一行是一个整数,表示操作的次数 n。  
接下来 n 行,每行表示一次操作。每行首先有一个整数 op 表示操作类型。
- 若 op = 1,则后面有一个整数 x,表示要将 x 加入数列。
- 若 op = 2,则表示要求输出数列中的最小数。
- 若 op = 3,则表示删除数列中的最小数。如果有多个数最小,只删除 1 个。

输出格式

对于每个操作2,输出一行一个整数表示答案。

样例 #1

样例输入 #1

5
1 2
1 5
2
3
2

样例输出 #1

2
5

提示

【数据规模与约定】
- 对于30%的数据,保证n ≤ 15。
- 对于70%的数据,保证n ≤ 10^{4}
- 对于100%的数据,保证1≤n≤10^{6},1≤x < 2^{31},op ∈ {1, 2, 3}。


分析:

这道题我们要知道的概念。

堆,其实就是一棵完全二叉树,如果你不理解,不妨看看百度

  堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看作一棵完全二叉树的数组对象。

  • 堆中某个结点的值总是不大于或不小于其父结点的值;

  • 堆总是一棵完全二叉树。

                                                                                                                -----百度百科

某个结点的值不大于其父结点的值被称为大根堆,如果不小于就称之为小根堆。

这下知道堆了吧 。

然后就是让我们执行3种操作:

1.往堆里加入元素

2.输出堆里最小的元素

3.删除最小的元素

第2种操作很简单,我就不讲了,我们就讲讲第1和第3个操作。

1.往堆里加入元素

这个其实没什么好讲的,见代码:

void push(int x)
{
	a[++n]=x;
	int u=n;
	while(u/2>0)
	{
		if(a[u/2]<x) break;
		swap(a[u],a[u/2]);
		u/=2;
	}
}

 2.删除最小的元素

这个操作就是找最小的数,要注意要判断是否有左子树和右子树

void pop()
{
	a[1]=a[n--];
	int u=1,t;
	while(1)
	{
		if(2*u<=n&&2*u+1<=n)
		{
			if(a[2*u]<a[2*u+1])
				t=2*u;
			else
				t=2*u+1;
		}
		else if(2*u<=n&&2*u+1>n)
			t=2*u;
		else break;
		if(a[u]<a[t]) break;
		else
		{
			swap(a[u],a[t]);
			u=t;
		}
	}
}

怎么样,会写代码了吧!


代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,a[N],op,x;
void push(int x)
{
	a[++n]=x;
	int u=n;
	while(u/2>0)
	{
		if(a[u/2]<x) break;
		swap(a[u],a[u/2]);
		u/=2;
	}
}
void pop()
{
	a[1]=a[n--];
	int u=1,t;
	while(1)
	{
		if(2*u<=n&&2*u+1<=n)
		{
			if(a[2*u]<a[2*u+1])
				t=2*u;
			else
				t=2*u+1;
		}
		else if(2*u<=n&&2*u+1>n)
			t=2*u;
		else break;
		if(a[u]<a[t]) break;
		else
		{
			swap(a[u],a[t]);
			u=t;
		}
	}
}
int main()
{
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>op;
		if(op==1)
		{
			cin>>x;
			push(x);
		}
		else if(op==2)
		{
			cout<<a[1]<<endl;
		}
		else if(op==3)
		{
			pop();
		}
	}
    return 0;
}

 如果有问题可以在评论区讨论!!

题目来源:洛谷P3378 【模板】堆,AC代码

你可以使用Dijkstra算法优化版本来解决最短路径问题。下面是一个C++模板示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; typedef pair<int, int> pii; // 用于表示图中的边 vector<int> dijkstra(vector<vector<pii>>& graph, int start) { int n = graph.size(); vector<int> dist(n, INT_MAX); // 初始化距离向量 vector<bool> visited(n, false); // 初始化访问标记向量 // 使用优先队列实现优化 priority_queue<pii, vector<pii>, greater<pii>> pq; dist[start] = 0; // 初始节点的距离为0 pq.push({0, start}); // 将初始节点加入优先队列 while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (visited[u]) { continue; } visited[u] = true; for (auto& edge : graph[u]) { int v = edge.first; int weight = edge.second; if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push({dist[v], v}); } } } return dist; } int main() { int n, m; cout << "请输入图中的节点数和边数: "; cin >> n >> m; vector<vector<pii>> graph(n); cout << "请输入每条边的起点、终点和权重: " << endl; for (int i = 0; i < m; i++) { int u, v, weight; cin >> u >> v >> weight; graph[u].push_back({v, weight}); graph[v].push_back({u, weight}); } int start; cout << "请输入起始节点: "; cin >> start; vector<int> shortestPath = dijkstra(graph, start); cout << "从起点到各个节点的最短距离为: " << endl; for (int i = 0; i < n; i++) { cout << "到节点 " << i << " 的最短距离为: " << shortestPath[i] << endl; } return 0; } ``` 你可以根据需要修改输入和输出的格式,以及将代码集成到你的项目中。这个模板使用了优先队列来实现优化,以提高Dijkstra算法的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值