Always keep a beginner's |

luckydrawbox

园龄:4个月粉丝:1关注:2

块状链表

使用前,请根据自己需要更改基本数据类型:

#define B_L_T int

以上实现了一个以 int\text{int} 为基本数据类型的块状链表定义。

为了实现输出元素值的操作,使用前请根据需要更改输出方式 put(val)\text{put}(val) 操作:

void put(B_L_T val){
	printf("%d ",val);
}

变量

  • tottot:块数。
  • ncinc_i:回收块内存。
  • sizesize:元素数量。
  • lenlen:块长,常为 size\sqrt{size}
  • max_lenmax\_len:块长限制系数,使块长不超过 max_len×lenmax\_len\times len,一般设在 121\sim 2 之间。
  • addiadd_i:插入的数字。
  • ee:空块。
  • aia_i:第 ii 个块:
    • ai.heada_i.head:指向前一个块。
    • ai.nexta_i.next:指向后一个块。
    • ai.lena_i.len:块长。
    • ai.bja_i.b_j:块内第 jj 个元素。

使用前要设定好 max_lenmax\_len

已经实现的操作

  • insert(p,n)\text{insert}(p,n):在第 pp 个数之后插入 nn 个数,这 nn 个数应该提前存入内置数组 add0n1add_{0\sim n-1} 中,时间复杂度 O(n+len+sizelen)O(n+len+\frac{size}{len})
  • remove(p,n)\text{remove}(p,n):删除从第 pp 个数开始的 nn 个数,超出部分不会改动,时间复杂度 O(len+sizelen)O(len+\frac{size}{len})
  • write(l,r)\text{write}(l,r):输出第 ll 到第 rr 个数,常用于调试,时间复杂度 O(rl+1+len+sizelen)O(r-l+1+len+\frac{size}{len})

可用于扩展的基本操作

块状链表灵活多变,可以使用以下基本操作扩展到其他操作。

  • build(p)\text{build}(p):在 pp 号块后新建一个节点,时间复杂度 O(1)O(1)
  • del(p)\text{del}(p):删除 pp 号块,块信息在被使用前不会改变,时间复杂度 O(1)O(1)
  • get(p)\text{get}(p):得到第 pp 个元素所在的块,并把 pp 改成在块内的下标,时间复杂度 O(len+sizelen)O(len+\frac{size}{len})
  • split(p,pos)\text{split}(p,pos):把第 pp 块分裂成 [0pos][0\sim pos][pos+1ap.len1][pos+1\sim a_p.len-1],第一块代替 pp,第二块在 pp 后面,时间复杂度 O(len)O(len)
  • merge(p)\text{merge}(p):合并 pp 块和 ap.nexta_p.next 块,要保证这两个块都存在,也就是 ppap.nexta_p.next 非零,时间复杂度 O(len)O(len)
#define B_L_T int
struct Block_List{
	int tot,nc[N],size,len;
	double max_len;
	struct Block{
		int head,next;
		int len;
		B_L_T b[2*N];
	}a[N],e;
	B_L_T add[M];
	Block_List(){
		tot=0;size=0;
		e.head=e.next=0;
		e.len=0;
		max_len=2;
		for(int i=1;i<N;i++)
			nc[i]=i;
	}
	int build(int p){
		int np=nc[++tot];
		a[np]=e;
		a[np].head=p;
		a[np].next=a[p].next;
		a[a[p].next].head=np;
		a[p].next=np;
		return np;
	}
	void del(int p){
		nc[tot--]=p;
		a[a[p].head].next=a[p].next;
		a[a[p].next].head=a[p].head;
	}
	int get(int &p){
		int kp=a[0].next;
		for(;kp;kp=a[kp].next)
			if(a[kp].len<p)
				p-=a[kp].len;
			else
				break;
		p--;
		return kp;
	}
	void split(int p,int pos){
		int np=build(p);
		a[np].len=pos;
		a[p].len-=a[np].len;
		for(int i=0;i<a[np].len;i++)
			a[np].b[i]=a[p].b[i+a[p].len];
	}
	void merge(int p){
		for(int i=0;i<a[a[p].next].len;i++)
			a[p].b[a[p].len+i]=a[a[p].next].b[i];
		a[p].len+=a[a[p].next].len;
		del(a[p].next);
	}
	void insert(int p,int n){
		n--; 
		if(p>size)
			return;
		size+=n+1;
		len=sqrt(size);
		int kp=get(p),nkp;
		if(p^(a[kp].len-1))
			split(kp,p);
		nkp=kp;
		for(int i=0;i<n/len;i++){
			nkp=build(nkp);
			a[nkp].len=len;
			for(int j=0;j<a[nkp].len;j++)
				a[nkp].b[j]=add[j+i*len];
		}
		nkp=build(nkp);
		a[nkp].len=n-n/len*len+1;
		for(int i=n/len*len;i<=n;i++)
			a[nkp].b[i-n/len*len]=add[i];
		for(;nkp&&(!kp||nkp!=a[kp].head);nkp=a[nkp].head){
			if(a[nkp].next&&a[nkp].len+a[a[nkp].next].len<max_len*len)
				merge(nkp);
		}
	}
	void remove(int p,int n){
		if(p>size)
			return;
		int l=p,r=min(p+n-1,size);
		size-=r-l+1;
		len=sqrt(size);
		int kl=get(l),kr=get(r);
		if(l){
			split(kl,l-1);
			kl=a[kl].next;
		}
		if(r^(a[kr].len-1))
			split(kr,r);
		for(int k=kl;k^a[kr].next;k=a[k].next)
			del(k);
		if(a[kl].head&&a[kr].next&&a[a[kl].head].len+a[a[kr].next].len<max_len*len)
			merge(a[kl].head);
	}
	void put(B_L_T val){
		printf("%d ",val);
	}
	void write(int l,int r){
		int lsl=l,lsr=r;
		int kl=get(l),kr=get(r);
		if(kl==kr){
			for(int i=l;i<=r;i++)
				put(a[kl].b[i]);
			return;
		}
		write(lsl,lsl+a[kl].len-1-l);
		for(int k=a[kl].next;k^kr;k=a[k].next)	
			for(int i=0;i<a[k].len;i++)
				put(a[k].b[i]);
		write(lsr-r,lsr);
	}
}K;

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526591

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(2)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起