【哈希表】【大/小顶堆】C++ 数据结构 无序图 优先队列

上次说好了写哈希表,但是只写哈希表好像内容又有点少,加一个大/小顶堆好了。虽然这俩好像关联不大哈哈哈


一、哈希表——无序图

C++11标准中并未加入hash_map的结构,那么哈希表的实现呢,我们用的是无序图(unordered_map)这个结构。unordered_map与集合同为关联容器,不同之处在于它的内部元素是无序的,是采用哈希表的结构来存储key的hash值。

1. 定义与初始化

使用时需要带头文件#include <unordered_map>
定义时需要明确键值和映射值的数据类型,映射值也可以是数组、链表等类型,可以用来存储键对应的多个数据。

unordered_map<char,int> freq;
unordered_map<char,int> freq1 (freq); //拷贝初始化
unordered_map<char,int> freq2 (freq.begin(),freq.end()); //范围初始化

2. 读取数据

再次强调,关联容器不能按位置访问元素,而且无序图内部元素是无序的。按键值查找或者插入的效率都很高。
一个常用的例子:求字符串中各字符出现的次数

string str="helloworld";
unordered_map<char,int> freq;
for(char i:str)
	freq[i]++; //没有的键会直接插入,映射值初始化为0,计数非常方便
//cout<<freq['o']; //单独访问,直接查找键值
for(auto [k,v]:freq) //遍历,k为键值,v为映射值,注意是方括号
	cout<<k<<"-"<<v<<endl;

运行结果:

r-1
e-1
d-1
o-2
h-1
w-1
l-3

3. 成员函数

bool isEmpty = freq.empty(); //判断是否为空
int num = freq.size(); //返回有效元素个数
freq.insert(pair<char,int>); //插入元素,参数为类型一致的pair
freq.erase(key); //删除元素,参数为键值
freq.clear(); //清空内容
int cnt = freq.count(); //返回匹配给定主键的元素的个数,只可能为0或1,用来判断某一键值是否存在

接着之前的例子:

pair<char,int> a('a',-1);
freq.insert(a);
freq.erase('l');
for(auto [k,v]:freq) //遍历,k为键值,v为映射值
	cout<<k<<"-"<<v<<endl;

运行结果:

r-1
e-1
d-1
o-2
h-1
a--1
w-1

二、大/小顶堆——优先队列

优先队列,顾名思义是一种特殊的队列,它的特殊之处就在于我们可以自定义队列中数据的优先级,让队列内元素按照优先级排列。

1.定义

既然是队列的一种,那么使用时当然需要带头文件#include <queue>

priority_queue<int> q; //默认为最大堆/大顶堆
priority_queue<int, vector<int>, greater<int>> q2; //小顶堆

如果数据类型不能直接比较,可以自定义排序方法:

struct cmp{
    bool operator ()(const vector<int>& a, const vector<int>& b)
    {
    	//注意:方法中定义用的大于,最后得到的是小顶堆,这个非常容易搞混,切记切记
        return a[1]>b[1] || a[1]==b[1] && a[2]>b[2];
    }
};
priority_queue<vector<int>, vector<vector<int>>, cmp> q;

类似地,如果是自定义的数据类型,也可以通过 “<” 运算符重载的方法来排序。举个栗子:

#include <iostream>
#include <queue>
using namespace std;
struct Node{ //自定义数据结构-二维坐标
    int x, y;
    Node(int a=0, int b=0):x(a), y(b) {}
};

bool operator<( Node a, Node b ){ //注意:"<"对应的是大顶堆,比如 a<b<c对应的是c在堆顶
    return a.x>b.x || a.x==b.x && a.y>b.y;
}

int main(){
    priority_queue<Node> q;
    q.push(Node(5, 5));
	q.push(Node(1, 2));
	q.push(Node(3, 5));
	q.push(Node(3, 2));
	q.push(Node(5, 1));
    while(!q.empty())
	{
        cout<< q.top().x <<","<< q.top().y <<endl;
        q.pop();
    }
    return 0;
}

运行结果:

1,2
3,2
3,5
5,1
5,5

2. 常用方法

和队列的常用方法基本相同,都是基础操作,就不举例子了。

//判空
q.empty()

//大小
q.size()

//插入
q.push(i)

//出队,即弹出最大值
q.pop()

//堆顶,即取最大值
q.top()

总结

哈希表可太常用了,用法一定一定要熟记。大/小顶堆在一些问题中可以得到很巧妙的解决方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值