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号节点是根节点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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;
}