2017-12-26 9 views
0

私はStringのいくつかのセットを作成し、これらのセットの一部を(usizeの)同じタグを持つようにマージしようとしています。私はマップを初期化したら、私は、文字列の追加を開始:Union-Find実装で親タグが更新されない

self.clusters.make_set("a"); 
self.clusters.make_set("b"); 

私はself.clusters.find("a")self.clusters.find("b")は、異なる値が返される呼び出すと、私はまだセットがマージされていないので罰金です。それから私は私が今self.clusters.find("a")self.clusters.find("b")を呼び出す場合、私は同じ値を取得する2組の

let _ = self.clusters.union("a", "b"); 

をマージするには、以下のメソッドを呼び出します。しかし、finalize()メソッドを呼び出してマップを反復しようとすると、セットをマージしなかったかのように元のタグが返されます。

self.clusters.finalize(); 

for (address, tag) in &self.clusters.map { 
    self.clusterizer_writer.write_all(format!("{};{}\n", address, 
    self.clusters.parent[*tag]).as_bytes()).unwrap(); 
} 

// to output all keys with the same tag as a list. 
let a: Vec<(usize, Vec<String>)> = { 
    let mut x = HashMap::new(); 
    for (k, v) in self.clusters.map.clone() { 
     x.entry(v).or_insert_with(Vec::new).push(k) 
    } 
    x.into_iter().collect() 
}; 

私はこれがなぜそのようなのか理解できませんが、私はRustに比較的新しいです。多分ポインターの問題?

"a"と "b"の代わりに、utils::arr_to_hex(&input.outpoint.txid)のようなものを実際に使用しています(String)。

これは、私が使用している連合の検索アルゴリズムの錆の実装です:

/// Tarjan's Union-Find data structure. 
#[derive(RustcDecodable, RustcEncodable)] 
pub struct DisjointSet<T: Clone + Hash + Eq> { 
    set_size: usize, 
    parent: Vec<usize>, 
    rank: Vec<usize>, 
    map: HashMap<T, usize>, // Each T entry is mapped onto a usize tag. 
} 

impl<T> DisjointSet<T> 
where 
    T: Clone + Hash + Eq, 
{ 
    pub fn new() -> Self { 
     const CAPACITY: usize = 1000000; 
     DisjointSet { 
      set_size: 0, 
      parent: Vec::with_capacity(CAPACITY), 
      rank: Vec::with_capacity(CAPACITY), 
      map: HashMap::with_capacity(CAPACITY), 
     } 
    } 

    pub fn make_set(&mut self, x: T) { 
     if self.map.contains_key(&x) { 
      return; 
     } 

     let len = &mut self.set_size; 
     self.map.insert(x, *len); 
     self.parent.push(*len); 
     self.rank.push(0); 

     *len += 1; 
    } 

    /// Returns Some(num), num is the tag of subset in which x is. 
    /// If x is not in the data structure, it returns None. 
    pub fn find(&mut self, x: T) -> Option<usize> { 
     let pos: usize; 
     match self.map.get(&x) { 
      Some(p) => { 
       pos = *p; 
      } 
      None => return None, 
     } 

     let ret = DisjointSet::<T>::find_internal(&mut self.parent, pos); 
     Some(ret) 
    } 

    /// Implements path compression. 
    fn find_internal(p: &mut Vec<usize>, n: usize) -> usize { 
     if p[n] != n { 
      let parent = p[n]; 
      p[n] = DisjointSet::<T>::find_internal(p, parent); 
      p[n] 
     } else { 
      n 
     } 
    } 

    /// Union the subsets to which x and y belong. 
    /// If it returns Ok<u32>, it is the tag for unified subset. 
    /// If it returns Err(), at least one of x and y is not in the disjoint-set. 
    pub fn union(&mut self, x: T, y: T) -> Result<usize,()> { 
     let x_root; 
     let y_root; 
     let x_rank; 
     let y_rank; 
     match self.find(x) { 
      Some(x_r) => { 
       x_root = x_r; 
       x_rank = self.rank[x_root]; 
      } 
      None => { 
       return Err(()); 
      } 
     } 

     match self.find(y) { 
      Some(y_r) => { 
       y_root = y_r; 
       y_rank = self.rank[y_root]; 
      } 
      None => { 
       return Err(()); 
      } 
     } 

     // Implements union-by-rank optimization. 
     if x_root == y_root { 
      return Ok(x_root); 
     } 

     if x_rank > y_rank { 
      self.parent[y_root] = x_root; 
      return Ok(x_root); 
     } else { 
      self.parent[x_root] = y_root; 
      if x_rank == y_rank { 
       self.rank[y_root] += 1; 
      } 
      return Ok(y_root); 
     } 
    } 

    /// Forces all laziness, updating every tag. 
    pub fn finalize(&mut self) { 
     for i in 0..self.set_size { 
      DisjointSet::<T>::find_internal(&mut self.parent, i); 
     } 
    } 
} 
+0

私は、このコードは最初の挿入後に 'map'フィールドを更新どこにも表示されません。 'find_internal'は' parent'を更新しますが、 'map'を直接反復することが目的であれば、これは役に立ちません。おそらく 'finalize'は、すべての値にわたってループ内の' find_internal'から返されたインデックスに各値の 'map'のインデックスを書き換える必要があります。別のデバッグ質問をするには、 'map'を反復するのではなく' find'を呼び出すと 'finalize'を呼び出した後に正しい情報を得ますか?おそらく、 'find_internal'を使って' DisjointSet'自体の特性として反復を実装したいでしょうか? –

+0

これらのヒントをありがとう。 self-clusters.parent(* tag)をself.clusters.find(address.clone())に置き換えました。同じ結果が得られました。 – Alessandro

+0

私はエラーがRustのユニークな機能に起因するとは思わないので、さまざまな点で値を出力することでこれをデバッグすることを提案したいと思います。例えば。 'finalize'の呼び出しの直後に' self.clusters.find( "a") 'と' self.clusters.find( "b") 'を呼び出すと、呼び出し前と同じことが返されますか?ここでの2番目のコメントは、私が考える直列化ループに当てはまります。私はself.clusters.map.clone()の '(k、v)for'という行を参照していました。シリアライゼーションループは 'map'の値を置き換えるものですか? –

答えて

1

私はあなたがちょうどあなたのDisjointSet正しく構造体のうち、情報を抽出していないと思います。

私はこれによってsnipedを取得し、ユニオンを実装しました。まず、基本的なUSIZEのimplementionで:より一般的な型のラッパーとその後

pub struct UnionFinderImpl { 
    parent: Vec<usize>, 
} 

pub struct UnionFinder<T: Hash> { 
    rev: Vec<Rc<T>>, 
    fwd: HashMap<Rc<T>, usize>, 
    uf: UnionFinderImpl, 
} 

どちらの構造体は、グループのVec<Vec<>>を返すgroups()メソッドを実装します。 Rcを使用したため、Cloneは不要です。

Playground

+0

非常に良いコード、テストケースを提供してくれてありがとう。ジェネリック型のfind_parentメソッドをどのように実装できますか? – Alessandro

+0

あなたの 'T'に対応する' usize'を見つけるために 'fwd'を使い、' uf.find_parent() 'を使って親' usize'を見つけ、次に 'rev'を使って親' usize'から'Rc '。 – NovaDenizen

関連する問題