1

私は C で柔軟な配列を実装しています。すべてのアイデアは、この小さなPaperに基づいています。私のエラーは、インデックス作成操作にあります。認めるにはあまりにも長い間ハッキングしていました。知識豊富な心と目を求める。

概要: データ構造は、データ ブロックへのポインタを保持する 1 つのフラット インデックス ブロックで構成されます。各データ ブロックのサイズは 2^(k/2) です。ここで、k は先頭のセット ビットです。したがって、要素「i」を検索すると、k は log_2(i+1) になります。

index = { 
    [0], -> [0]
    [2],  -> [0,1]
    [2],  -> [0,1]
    [3],  -> [0,1,2,3]
    [4],  -> [0,1,2,3]
    ....}

各データ ブロックのサイズは、クラスタ化される「スーパー ブロック」によって決まります。スーパーブロックは、同じサイズのデータ​​ブロックで構成されています。そう。インデックス 1,2 は同じスーパー ブロック (スーパー ブロック 1) 内にあります。0 (スーパーブロック 0) とインデックス 3 (スーパーブロック 2) は違います。

各スーパーブロックには 2^(floor(k/2)) データ ブロックがあり、これらの各データ ブロックのサイズは 2^(ceil(k/2)) になります。

問題 r = 2 の累乗の場合、インデックスは本来あるべきものをスキップします。3 を検索するときのようにindex [2][0]、 ではなくindex[3][0]. なぜこれが起こるのですか?それを回避する方法はありますか?「off by 1」というエラーが表示されていませんか??

コード ここにあるのは単一のメイン関数testcaseです。これは明確でシンプルで、インデックス 3 の要素を取得しようとすると失敗します。

検索インデックス i の簡略化されたコードは次のとおりです。

/* Edited from the actual test case for extra clarity */
/* all vars int */
r= i+1
k = first_set_bit(r) - 1;   // ex: r = 5, 5 = "00000101"b so k is (3-1) = 2

b = first_subset_of_r(floor(k/2)); // floor(k/2) bits of r immediately after first set; 
e = last_subset_of_r(ceil(k/2); // last ceil(k/2) bits of r 
p = (1 << k) -1 ; // 2^k -1
// Index supposed to be found with. . .
return index[p+b][e];

これは実際の出力です。最初に配列の内容をインデックスとデータ ブロックで出力し、次に 4 回の出力でインデックスを試行します。

最初の部分は 2 次元配列をダンプします。バーの前の数字はインデックス ブロックのインデックスであり、後の部分はインデックス ブロックが指す配列に含まれる要素です。すべての配列のインデックスはゼロです。

[clemensm@gaia:23]> ./a.out 
Index block |  element number (Not it's index!)
0 | 0   
1 | 1   2   
2 | 3   4   
3 | 5   6   
4 | 7   8   9   10  
5 | 11  12  13  14  
6 | 15  16  17  18  
7 | 19  20  21  22  
8 | 23  24  25  26  
9 | 27  28  29  30  
10 | 31  32  33  34  35  36  37  38  
11 | 39  40  41  42  43  44  45  46  
12 | 47  48  49  50  51  52  53  54  
13 | 55  56  57  58  59  60  61  62  
14 | 63  64  65  66  67  68  69  70  
15 | 71  72  73  74  75  76  77  78  
16 | 79  80  81  82  83  84  85  86  
17 | 87  88  89  90  91  92  93  94  
18 | 95  96  97  98  99  100 101 102 
19 | 103 104 105 106 107 108 109 110 
Finished element dump

Trying to get 0
R: [1]b
k/2=[0], Ceil(k,2)=[0]
K: [0] is the leading 1 bit
B: [0]
E: [0]
P: [0] data blocks prior to our superblock
p+b,e : [0,0] 

Trying to get 1
R: [10]b
k/2=[0], Ceil(k,2)=[1]
K: [1] is the leading 1 bit
B: [0]
E: [0]
P: [1] data blocks prior to our superblock
p+b,e : [1,0] 

Trying to get 2
R: [11]b
k/2=[0], Ceil(k,2)=[1]
K: [1] is the leading 1 bit
B: [0]
E: [1]
P: [1] data blocks prior to our superblock
p+b,e : [1,1] 

Trying to get 3
R: [100]b
k/2=[1], Ceil(k,2)=[1]
K: [2] is the leading 1 bit
B: [0]
E: [0]
P: [3] data blocks prior to our superblock
p+b,e : [3,0] 
a.out: test_array.c:81: main: Assertion `get_index(3)==3' failed.
Abort (core dumped)
4

1 に答える 1

3

検索エンジンと明確さのためだけに、紙の名前:Resizable Arrays in Optimal Time and Space
私が紙から見る限り、ここで非常に基本的な経験をすることができます。見栄えの良い紙であっても、間違いがある可能性があります。

ロケートアルゴリズムは明らかに間違っています。前にデータブロックの数を計算すると主張する3行目は、SB_kこの方法では機能しません。これは、上記の例ですでに見られます。

自分で式を見つけて、その後も読み続けることをお勧めします。

私の分析はこの公式を示唆しています:

p = 2^(k/2 + 1) - 2 + (k mod 2) * 2^(k/2) # "/" indicates integer division

サンプルコード:

int max = 20;
for (int k = 0; k < max; k++)
    System.out.println("k=" + k + " - data blocks: " + Math.pow(2, k/2) + " - data blocks size: " + Math.pow(2, Math.ceil(k/2.0)));
System.out.println();

for (int i = 0; i < max; i++) {
    String r = Integer.toBinaryString(i + 1);
    int k = r.length() - 1;
    String b_bin = r.substring(1, 1 + k/2);
    int b = Integer.parseInt("0" + b_bin, 2);
    String e_bin = r.substring((int)Math.ceil(k / 2.0));
    int e = Integer.parseInt("0" + e_bin, 2);
    int p = (1 << (k/2 + 1)) - 2 + (k & 1) * (1 << (k/2));
    int db = p + b;
    System.out.println("i=" + i + ", r=" + r + ", k=" + k + ", b_bin=" + b_bin + ", b=" + b + ", e_bin=" + e_bin + ", e=" + e + ", p=" + p + ", db=" + db);
}

サンプル結果:

k=0 - data blocks: 1.0 - data blocks size: 1.0
k=1 - data blocks: 1.0 - data blocks size: 2.0
k=2 - data blocks: 2.0 - data blocks size: 2.0
k=3 - data blocks: 2.0 - data blocks size: 4.0
k=4 - data blocks: 4.0 - data blocks size: 4.0
k=5 - data blocks: 4.0 - data blocks size: 8.0
k=6 - data blocks: 8.0 - data blocks size: 8.0
k=7 - data blocks: 8.0 - data blocks size: 16.0
k=8 - data blocks: 16.0 - data blocks size: 16.0
k=9 - data blocks: 16.0 - data blocks size: 32.0
k=10 - data blocks: 32.0 - data blocks size: 32.0
k=11 - data blocks: 32.0 - data blocks size: 64.0
k=12 - data blocks: 64.0 - data blocks size: 64.0
k=13 - data blocks: 64.0 - data blocks size: 128.0
k=14 - data blocks: 128.0 - data blocks size: 128.0
k=15 - data blocks: 128.0 - data blocks size: 256.0
k=16 - data blocks: 256.0 - data blocks size: 256.0
k=17 - data blocks: 256.0 - data blocks size: 512.0
k=18 - data blocks: 512.0 - data blocks size: 512.0
k=19 - data blocks: 512.0 - data blocks size: 1024.0

i=0, r=1, k=0, b_bin=, b=0, e_bin=1, e=1, p=0, db=0
i=1, r=10, k=1, b_bin=, b=0, e_bin=0, e=0, p=1, db=1
i=2, r=11, k=1, b_bin=, b=0, e_bin=1, e=1, p=1, db=1
i=3, r=100, k=2, b_bin=0, b=0, e_bin=00, e=0, p=2, db=2
i=4, r=101, k=2, b_bin=0, b=0, e_bin=01, e=1, p=2, db=2
i=5, r=110, k=2, b_bin=1, b=1, e_bin=10, e=2, p=2, db=3
i=6, r=111, k=2, b_bin=1, b=1, e_bin=11, e=3, p=2, db=3
i=7, r=1000, k=3, b_bin=0, b=0, e_bin=00, e=0, p=4, db=4
i=8, r=1001, k=3, b_bin=0, b=0, e_bin=01, e=1, p=4, db=4
i=9, r=1010, k=3, b_bin=0, b=0, e_bin=10, e=2, p=4, db=4
i=10, r=1011, k=3, b_bin=0, b=0, e_bin=11, e=3, p=4, db=4
i=11, r=1100, k=3, b_bin=1, b=1, e_bin=00, e=0, p=4, db=5
i=12, r=1101, k=3, b_bin=1, b=1, e_bin=01, e=1, p=4, db=5
i=13, r=1110, k=3, b_bin=1, b=1, e_bin=10, e=2, p=4, db=5
i=14, r=1111, k=3, b_bin=1, b=1, e_bin=11, e=3, p=4, db=5
i=15, r=10000, k=4, b_bin=00, b=0, e_bin=000, e=0, p=6, db=6
i=16, r=10001, k=4, b_bin=00, b=0, e_bin=001, e=1, p=6, db=6
i=17, r=10010, k=4, b_bin=00, b=0, e_bin=010, e=2, p=6, db=6
i=18, r=10011, k=4, b_bin=00, b=0, e_bin=011, e=3, p=6, db=6
i=19, r=10100, k=4, b_bin=01, b=1, e_bin=100, e=4, p=6, db=7

編集:数式への道についての詳細

数式を取得する方法(私はすべてのステップを読んで、あなたが自分で続けることができるかどうかを考えることをお勧めします、そうでない場合は踏み続けることをお勧めします):
論文は次のように述べています:"When superblock SB_k is fully allocated, it consists of 2^floor(k/2) data blocks"

SB_kより前のデータブロックの数が必要な場合は、それらすべてを合計する必要があります。

p = sum from i=0 to k-1 over 2^floor(i/2)

これを使用できるようになりました。これは明確なforループステートメントです。しかし、それを単一の計算にしましょう。
合計を考えると、フロアの関係で2^iごとに2回合計されます。これは、すべての偶数kにも当てはまります。これは、合計maxが不均一であるため、floor((k-2)/2) = floor((k-1)/2)です。奇数kの場合、1つの数値があり、これを個別に考慮する必要があります。

だから、私たちは今持っています:

(2 * sum from i=0 to floor((k-2)/2) over 2^i) + (k mod 2)*2^k/2

(詳細が必要な場合は、k = 6,7,8の例をいくつか作成してください)

これで、合計を明確に取り除くことができますsum from i=0 to n over 2^i = 2^(n+1) - 1(これは基本的な数学/計算機の証明です。バイナリ表現から正確さを明確に確認できます)。この式を使用して、次の式を取得します。

2 * (2^(floor((k-2)/2) + 1) - 1) + (k mod 2)*2^k/2

これで、2を掛けて、指数を変更できます。これで完了です。

2^(floor(k/2) + 1) - 2 + (k mod 2)*2^k/2

これがお役に立てば幸いです。

于 2012-10-29T23:55:04.887 に答える