【C++算法】桶、桶排序、map详细讲解,带例题和详细注释

1)桶结构

  • 当数组中每个元素的大小范围给定时并且不超过空间限制时,用该数组的下标或下标+偏移量映射为该值的大小,数组的值表示该数字出现的次数的数据结构
  • 优点:有效提高数据的访问效率和处理速度
  • 缺点:必须知道每个元素的大小范围并且能够映射到 [ 0 , N ] [0,N] [0,N]才可以使用

一本通 1186:出现次数超过一半的数

1:桶做法
#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

// 解题思路: 

// 数据范围是(-50,50),即[-49,49],但下标不可能从0开始
// 所以需要加偏移量50映射到[1,99]
const int N=1e2+10;
int a[N]; // 桶
// 什么时候用桶→每个数据的范围给定
// 下标代表这个数字,或者这个数字的映射值,数组的值代表出现的次数

// 排序:冒泡/交换/选择 O(n²), 快排/希尔排序/归并排序O(nlogn)/sort, 桶排序O(n)

int main() {
	int n;
	cin>>n; // 假设五个元素分别是5: 2 4 2 5 9
	for(int i=1;i<=n;i++) {
		int temp;
		cin>>temp;
		a[temp+50]++; // 那么a[2]=2,a[4]=1,a[5]=1,a[9]=1
	}
	// 遍历所有可能的大小,其实就遍历了所有的数字
	// 如果根本没出现过,a[i]=0
	bool flag=false;
	for(int i=1;i<=99;i++) {
		// a[i]代表出现的次数
		if(a[i]>n/2) {
			flag=true;
			cout<<i-50; // 减去偏移量
		} 
	}
	if(flag==false) cout<<"no";
	return 0;
}
2:map做法
  • m a p map map C + + C++ C++ STL库中自带的一种数据结构,可以理解为 P y t h o n Python Python中的 d i c t dict dict字典数据结构,map中有两个关键字,一个是键(索引),一个是键值,它是一个二元组,和本题不谋而合,让第一个关键字存储这个值的大小,第二关键字存储出现的次数即可,而且不用考虑从 [ − 49 , 49 ] [-49,49] [49,49]映射到 [ 1 , 99 ] [1,99] [1,99]
#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

// 解题思路: 

const int N=1e5+5;

int main() {
	map<int,int> m;
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) {
		int temp;
		cin>>temp;
		m[temp]++; // temp作为索引,键值+1
	}
	bool flag=false;
	// 遍历map中的所有元素,迭代器的方法遍历
	for(auto it=m.begin();it!=m.end();it++) {
		if(it->second>n/2) {
			flag=true;
			cout<<it->first;
		}
	}
	if(flag==false) cout<<"no";
	return 0;
}

2)桶排序

  • 当数据入桶后其实就相当于已经排好了序,我们可以从元素最小值遍历到最大值,又因为桶中的元素代表着这个元素出现的次数,那么出现了多少次我们就输出多少次这个元素,又因为是从小到大遍历的,所以倒桶的过程就是桶排序
  • 桶排序的时间复杂度是 O ( n ) O(n) O(n),其中n是元素个数
#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

// 解题思路: 假设每个元素的大小范围是[1,1000],我们准备一个大小足够的桶
 
const int N=1e3+5; 
int a[N];

int main() {
	int n;
	cin>>n;
	while(n--) {
		int temp;
		cin>>temp;
		// 入桶
		a[temp]++;
	}
	// 倒桶的过程即为排序,不是真正的排好序
	// 从小到大遍历下标,即less规则排序
	// 从大到小遍历下标,即greater规则排序
	for(int i=1;i<=1000;i++) {
		// 如果i这个数字出现过
		if(a[i]) {
			for(int j=a[i];j>0;j--) {
				// 输出a[i]次,因为a[i]代表i出现的次数
				cout<<i<<' ';
			}
		}	
	}
	return 0;
}
  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值