首先,块状链表是数组和链表的结合体。我们知道,在数组中删除,插入一个元素的复杂度是O(n),在链表中,插入和删除的复杂度是O(1)。 而在链表中,查找的复杂度是O(n)的,数组中是O(1)的。于是就有人想到一个方法,把数组放在链表里面,形成块状链表。这里给出结论,块状数组的查询删除插入复杂度为O(x+N/x) 这里的x为块的大小N为元素个数。
在普通链表里面 data1 -->data2-->data3-------- 块状链表里面 data1【n】-->data2【n】------
我们先用C++里面的容器来生成动态数组会比较好一点。并且,像链表一样,写一个next,不过在这里我是用数组存下一个地址的,当然用指针也是可以的。既然,我用数组,那么我一开始就必须得初始化一下这个next数组了,并且全都至为0。方便后面的操作。
我们先讲插入,如果我们的插入位置,小于第一块块状链表里面的数组大小的话,那么我们就插在这一块。如果插入位置超出了这一块,那么我们就顺着next数组指向的地址去插入下一块块状数组里面的数组。如果还是没有就一直找下去,直到出现可以插入的位置。并且,最重要的是,在插入的时候如果这个数组的大小超过了我们想要分配的数组的大小,我们就要进行分割了。做法也很简单,就是将后半段的数据直接丢到下一个块里面去就好了。这个时候必然会有分割块所占区域小于我们想要分割的大小。
接下来就是读取数据了。这个和插入差不多,就是属于找位置,如果超过第一块的数组大小的话,就去找连接的那块,就一直找下去,直到找到自己的位置。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int maxlen; //由均值不等式得 O(x+n/x) x=sqrt(n)得时候时间复杂度最低。
int n;
struct node
{
int next[maxn];
vector<int> block[maxn];
int top;
node()
{
clear();
}
void clear()
{
for(int i = 0; i<maxn ; i++)
{
next[i]=0;
block[i].clear();
}
top=1;
}
void insert(int index,int value)
{
int id=1;
while(id)
{
if(index <= block[id].size())
{
block[id].insert(block[id].begin()+index,value);
if(block[id].size()>maxlen)
{
sqlit(id);
}
return ;
}
else
{
index-=block[id].size();
id = next[id];
}
}
}
void sqlit(int id)
{
top++;
int siz = block[id].size()/2;
block[top].assign(block[id].begin()+siz,block[id].end()); //替换
block[id].resize(siz);//清除 siz后面的。
next[top] = next[id];
next[id] = top;
}
int get(int index)
{
int id=1;
while(id)
{
if(index < block[id].size())
{
return block[id][index];
}
else
{
index-=block[id].size();
id = next[id];
}
}
}
void dele(int index)
{
int id = 1;
while(id)
{
if(block[id].size() > index)
{
block[id].erase(block[id].begin()+index);
return ;
}
else
{
index -=block[id].size();
id = next[id];
}
}
}
} arr;
int main()
{
int q;
scanf("%d %d",&n,&q);
maxlen=sqrt(n)+1;
for(int i = 0 ;i<n;i++)
{
int x;
scanf("%d",&x);
arr.insert(i,x);
}
cout << arr.get(5) <<endl;
}