【算法笔记】堆排序,哈希存储的俩种实现方式(推荐开放定址法)

1. 哈希表

把范围比较大的数映射到范围比较小的范围中。

1.1. 存储结构

1.1.1 开放寻址法(用的比较多)

只开一个一维数组。要求数组的长度是数据长度的俩到三倍。
思路:和上厕所找坑位差不多,先选择一个自己想去的位置(也就是哈希函数对应的位置)找到了这个位置之后,如果位置有人,那就看看边上的位置能不能进去,如果没有人,那就进去。
区别:find函数返回的是:
如果有x这个元素,那么返回的是x这个元素对应的下标
如果没有x这个元素,那么返回的是x可以插入的位置

#include<iostream>
#include<cstring>
using namespace std;
const int N=200003;
int indx=0;
int e[N];
const int null = 0x3f3f3f3f;

int has(int x){
	return (x%N +N)%N;
}


int find_(int x){
	int i=has(x);
	while(e[i]!=null&&e[i]!=x){
		++i;
		if(i==N) i=0;
	}
	return i;
}

int main(){
	memset(e,0x3f3f3f3f,sizeof e);
	int n;
	cin>>n;
	while(n--){
		char op[2];
		int x;
		scanf("%s%d",op,&x);
		int i=find_(x);
		if(*op=='I'){
			e[i]=x;
		}else{
		
		if(e[i]==null){
			cout<<"No"<<endl;
		}else{
			cout<<"Yes"<<endl;
		}
			
		}		
		
	}	
	return 0;
}

1.1.2 拉链法

开辟一个一维数组,存储所有的哈希值。这么取冲突的概率最小。

思路:为每个节点维护一个头指针,插入元素的时候采用头插法,这样省去了尾指针的维护。这里和数组模拟单链表的方式是一样的(这个思路非常重要!!!!)

#include<iostream>
#include<cstring>
using namespace std;
const int N=100003;
int indx=0;
int head[N];
int e[N];
int ne[N];
int has(int x){
	return (x%N +N)%N;
}
void insert_(int x){
	int i= has(x);
	e[indx]=x;
	ne[indx]=head[i];
	head[i]=indx++;
}
bool find_(int x){
	int k =has(x);
	for(int i=head[k];i!=-1;i=ne[i]){
		if(e[i]==x){
			return true;
		}
	} 
	return false;
}
int main(){
	memset(head,-1,sizeof head);
	int n;
	cin>>n;
	while(n--){
		char op[2];
		int x;
		scanf("%s%d",op,&x);
		if(*op=='I'){
			insert_(x);
		}else{
		
			if(find_(x)){
				cout<<"Yes"<<endl;
			}else{
				cout<<"No"<<endl;
			}
		}	
	}

	return 0;
}

2. 设计一个堆

2.1 如何手写一个堆?

  1. 插入一个数

  2. 求集合中的最小值

  3. 删除最小值

  4. 删除任意一个元素

  5. 修改任意一个元素

  6. 堆的存储

    顺序存储的方式,1号节点是根节点。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9f0jdzZG-1673711063182)(C:\Users\小米\AppData\Roaming\Typora\typora-user-images\image-20230114191554307.png)]

down操作:与孩子节点比较,如果当前节点比孩子节点大,则交换。

up操作:与父节点比较,如果当前节点比父节点小则交换。

如果想插入一个数:heap[++size]=x;up(size)

求当前堆中的最小值:heap[1];

删除一个元素:把最后一个元素放到堆顶,然后size–最后再对堆顶元素进行down(1)操作。

删除任意元素:假设我们要删除第K个节点,heap[k]=heap[size];size–;down(k);up(k);

#include<iostream>
using namespace std;
const int N = 1000010;
int heap[N];
int size_=0;
int ph[N];//表示第K个插入的数在堆里面的下标是什么
int hp[N];//表示在堆中的下标为某个数的点是第几个插入的点。 
void exchange_(int u,int t){
	int a = hp[u];
	int b = hp[t];
	swap(ph[a],ph[b]);
	swap(hp[u],hp[t]);
	swap(heap[u],heap[t]);
}
void down(int u){
	int t = u;
    if(u*2<=size_&&heap[u*2]<heap[t])t=u*2;
    if(u*2+1<=size_&&heap[u*2+1]<heap[t])t=u*2+1;
    if(u!=t){
    	exchange_(u,t);
    	down(t);
	}
}
void up(int u){
	int t=u;
	if(u/2>0&&heap[u]<heap[u/2])t=u/2;
	if(t!=u){
		exchange_(u,t);
	//	swap(heap[u],heap[t]);
		up(t);
	}
}
int main(){
	int m;
	int n;
	cin>>m;
		int cnt=0;
//	cin>>n;
	for(int i=1;i<=m;++i){
		string st;
		cin>>st;
		if(st=="I"){
			int x;
			cin>>x;
			++cnt;
			heap[++size_]=x;
			ph[cnt]=size_; 
			hp[size_] =cnt;
			up(size_);
			continue;
		}
		if(st=="PM"){
			cout<<heap[1]<<endl;;
			continue;
		}
		if(st=="DM"){
			exchange_(size_,1);
	//		swap(heap[size_],heap[1]);
			--size_;
			down(1);
			continue;
		}
		if(st=="D"){
			int k;
			cin>>k;
			k=ph[k];
			exchange_(k,size_);
		//	swap(heap[ph[k]],heap[size_]);
			size_--;
			//ph[hp[size_]]=0;
			down(k);
			up(k);
			continue;
		}
		if(st=="C"){
			int k;
			int x;
			cin>>k;
			cin>>x;
			heap[ph[k]]=x;
			down(ph[k]);
			up(ph[k]);
		}
	}
	int i;
	for(i=m/2;i>=1;--i){
		down(i);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值