POJ2887 塊狀數組

1 題意

給出一個長串,然後給出n個操作,操作有兩種,在某個位置插入一個字符,或者查詢第x個位置上的字符是什麼

2分析

(1)

快速輸出第x個位置上的字符,像直接存儲類數據結構中的數組就可以,但是難在插入一個字符時,後面所有字符都要動,所以不能用普通的數組;

而如果用鏈表雖然能解決插入不超時的問題,但是因爲是順序存儲類結構,所以不能很快的輸出第x個位置上的字符。

這裏採用塊狀數組,數組塊數*每個塊的最大長度>=總的元素+操作個數,即分塊以後,每個塊都有個增大的空間(讓其大於操作個數即可),然後再用一個sum[]數組,統計從第一塊到當前塊的元素的數量,查找或插入某個元素時,通過輸入的x(第x個),利用遞增的sum數組進行二分,得到塊號,然後x-sum[cur-1]就得到在該塊內的第幾個,如果查找就返回查找結果,如果輸出就只操縱當前快即可。

(2)下面給出兩份代碼,代碼一是塊數和塊內元素都從1開始;代碼二是塊數和快內元素都從0開始,後者要在細節上多處理一下。

(3)易錯點:

①即塊數和塊內元素從0還是1開始。

②Init()中,block_num應該是先將輸入的串的長度+操作個數,然後再開方;而不是先將串的長度開方之後再加操作個數。個人認爲後者導致runtime error的原因是因爲這樣做的話,導致棧溢出(算了一下,如果是上限1M的棧,就很可能會溢出),相當於每個塊的長度都給到最壞情況下需要的長度,而前者只是給每個塊的長度設定爲平均情況下需要的長度。具體採用哪一種,應該根據題目給出的數據推一下吧,如果不溢出就用後者,如果溢出,那麼只能用前者。

summary:

a.

block_len,即各個塊的最大長度——Block中dat[]的長度:

在最壞情況下=sqrt(str)+n;

在平均情況下=sqrt(str+n);

b.

block_num,塊數:

準確講,=(str+n)/block_len

結合a中的平均情況來講,block_num=block_len=sqrt(str+n)、

3

代碼一

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=1010;
int block_len,block_num;//每一塊的長度、塊數
int n;//操作個數
int sum[maxn];
char str[1000010];
void maintain();
struct Blocks{
    int size_;//個數
    char dat[maxn<<1];//2020;
    void Push_back(char zifu){
        dat[++size_]=zifu;
    }
    void Insert(int pos,char zifu){
        if(pos>size_)   dat[++size_]=zifu;
        else{
            for(int i=++size_;i>pos;i--)
                dat[i]=dat[i-1];
            dat[pos]=zifu;
        }
        maintain();
    }
    //void Delate(){}
    char Query(int pos){
        return dat[pos];
    }
}block[maxn];
void maintain(){
    sum[1]=block[1].size_;
    for(int i=2;i<=block_num;i++)
        sum[i]=sum[i-1]+block[i].size_;
}
void Init(){
    int str_len=strlen(str);
    block_len=block_num=sqrt( (str_len+n)*(1.0) ) ;///in fact,block_len應該是struct Blocks中的dat[]的長度,但是因爲不是const,所以提前根據題目條件算出了個最大的數值限定了dat[]的長度
    //block_len=block_num=sqrt( (str_len)*(1.0) )+n ;
    for(int i=1;i<=block_num;i++){
        block[i].size_=0;
        sum[i]=0;
    }
    for(int i=0;i<str_len;i++){
        block[i/block_len +1].Push_back(str[i]);
    }
    maintain();
}
int main()
{
    while(~scanf("%s",str)){
        //gets(str);
        int pos;
        char com[3],s[3];
        scanf("%d",&n);
        Init();
        for(int i=1;i<=n;i++){
            scanf("%s",com);
            int kuai_id,kuai_in_pos;
            if(com[0]=='Q'){
                scanf("%d",&pos);
                kuai_id=lower_bound(sum+1,sum+1+block_num,pos)-sum;
                kuai_in_pos=pos-sum[kuai_id-1];
                cout<<block[kuai_id].Query(kuai_in_pos)<<endl;
            }
            else{
                scanf("%s%d",s,&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                kuai_in_pos=pos-sum[kuai_id-1];
                block[kuai_id].Insert(kuai_in_pos,s[0]);
            }
        }
    }
    return 0;
}

代碼二

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

const int maxn=1010;
int block_len,block_num;//每一塊的長度、塊數
int n;//操作個數
int sum[maxn];
char str[1000010];
void maintain();
struct Blocks{
    int size_;//個數
    char dat[maxn<<1];//2020;
    void Push_back(char zifu){
        dat[size_++]=zifu;
    }
    void Insert(int pos,char zifu){
        if(pos>=size_)   dat[size_++]=zifu;
        else{
            for(int i=size_;i>pos;i--)
                dat[i]=dat[i-1];
            dat[pos]=zifu;
            size_++;
        }
        maintain();
    }
    //void Delate(){}
    char Query(int pos){
        return dat[pos];
    }
}block[maxn];
void maintain(){
    sum[0]=block[0].size_;
    for(int i=1;i<=block_num;i++)
        sum[i]=sum[i-1]+block[i].size_;
}
void Init(){
    int str_len=strlen(str);
    block_len=block_num=sqrt( (str_len+n)*(1.0) ) ;///in fact,block_len應該是struct Blocks中的dat[]的長度,但是因爲不是const,所以提前根據題目條件算出了個最大的數值限定了dat[]的長度
    //block_len=block_num=sqrt( (str_len)*(1.0) )+n ;
    for(int i=0;i<=block_num;i++){
        block[i].size_=0;
        sum[i]=0;
    }
    for(int i=0;i<str_len;i++){
        block[i/block_len].Push_back(str[i]);
    }
    maintain();
}
int main()
{
        gets(str);
        int pos;
        char com[3],s[3];
        scanf("%d",&n);
        Init();
        for(int i=1;i<=n;i++){
            scanf("%s",com);
            int kuai_id,kuai_in_pos;
            if(com[0]=='Q'){
                scanf("%d",&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                if(kuai_id==0)
                    kuai_in_pos=(pos-1);
                else
                    kuai_in_pos=pos-sum[kuai_id-1]-1;
                cout<<block[kuai_id].Query(kuai_in_pos)<<endl;//pos-sum[kuai_id-1]是第幾個,再-1得到塊內的位置
            }
            else{
                scanf("%s%d",s,&pos);
                kuai_id=lower_bound(sum,sum+block_num,pos)-sum;
                 if(kuai_id==0)
                    kuai_in_pos=(pos-1);
                else
                    kuai_in_pos=pos-sum[kuai_id-1]-1;
                block[kuai_id].Insert(kuai_in_pos,s[0]);//pos-sum[kuai_id-1]是第幾個,再-1得到塊內的位置
            }
        }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章