2009-12-25 72 views
2

Java中是否存在類似於雙面列表的東西?也許第三方實施?Java中的雙面(雙向)列表

這裏有一個小例子來展示我的想法。

原始狀態:

 
A: 0-1-2-3 
    | | | | 
B: 0-1-2-3 

在乙去除元件1的後:

 
    Null 
    | 
A: 0-1-2-3 
    |// 
B: 0-1-2 

的數據結構必須從兩側接近。所以它更多的是雙向映射和列表的組合。我想: a)使用兩個存儲Integer對象的列表。缺點是必須始終保持同步。 b)使用Apache Commons的BidiMap。缺點在於它是未排序的,並且當元素被移除時(更新其他標註),其行爲不像列表。

+0

如果您對預期行爲給出了更精確/詳細的定義,則可能會得到更多答案。 – 2009-12-25 09:14:41

+0

準確地說,你是否想要一個雙向映射,它將另一邊的零位清零,並完全從另一邊刪除條目? – Esko 2009-12-25 09:31:12

+0

它更像是兩個相互連接的列表。一個列表的值是另一個的索引。如果刪除了列表B的一個索引,則列表A的相應索引(它也是列表B的元素)被設置爲空(或-1或類似的東西)。 – Zardoz 2009-12-25 14:02:33

回答

0

最後我用兩個列表來保存從每個站點查看的位置。 由於我總是隻修改其中一個列表,另一個將被重新計算。 下面的完整代碼(如果有人感興趣)。它嵌入到JFace文檔類中,但是邏輯也可以在其他地方實現。

public class AdaptedDocument extends AbstractDocument implements IDocumentListener { 

private IDocument masterDocument; 

private List<Integer> masterToSlaveMapping; 
private List<Integer> slaveToMasterMapping; 

private boolean setMaster = true; 
private boolean replaceMaster = true; 

public AdaptedDocument(IDocument masterDocument) { 

    super(); 

    this.masterDocument = masterDocument; 
    masterDocument.addDocumentListener(this); 

    setTextStore(new CopyOnWriteTextStore(new GapTextStore())); 
    setLineTracker(new DefaultLineTracker()); 
    getStore().set(masterDocument.get()); 
    getTracker().set(masterDocument.get()); 
    initializeMappings(); 
    completeInitialization(); 
} 

private void initializeMappings() { 

    masterToSlaveMapping = new ArrayList<Integer>(); 
    slaveToMasterMapping = new ArrayList<Integer>(); 

    for (int i=0; i<masterDocument.getLength(); i++) { 
     masterToSlaveMapping.add(i); 
     slaveToMasterMapping.add(i); 
    } 
} 

@Override 
public void replace(int pos, int length, String text) throws BadLocationException { 
    if (replaceMaster) { 
     masterDocument.replace(pos, length, text); 
    } 
    super.replace(pos, length, text); 
} 

@Override 
public void replace(int pos, int length, String text, long modificationStamp) throws BadLocationException { 
    if (replaceMaster) { 
     masterDocument.replace(pos, length, text); 
    } 
    super.replace(pos, length, text, modificationStamp); 
} 

@Override 
public void set(String text) { 
    if (setMaster) { 
     masterDocument.set(text); 
    } 
    super.set(text); 
} 

@Override 
public void set(String text, long modificationStamp) { 
    if (setMaster) { 
     if (masterDocument instanceof AbstractDocument) { 
      ((AbstractDocument) masterDocument).set(text, modificationStamp); 
     } 
     else { 
      masterDocument.set(text); 
     } 
    } 
    super.set(text, modificationStamp); 
} 

public IDocument getMasterDocument() { 
    return this.masterDocument; 
} 

public void removeTextFromSlave(int offset, int length) throws BadLocationException { 

    if (length == 0) { 
     return; 
    } 

    try { 
     replaceSlaveOnly(offset, length, ""); 

     for (int i=0; i<length; i++) { 
      slaveToMasterMapping.remove(offset); 
     } 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 

    rebuildMasterToSlaveMapping(); 
} 

public void addTextToSlaveOnly(int offset, String text) throws BadLocationException { 

    try {  
     replaceSlaveOnly(offset, 0, text); 

     for (int i=0; i<text.length(); i++) { 
      slaveToMasterMapping.add(offset + i, -1); 
     } 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 

    rebuildMasterToSlaveMapping(); 
} 

public void removeMasterDocumentRange(int offset, int length) throws BadLocationException { 

    if (length == 0) { 
     return; 
    } 

    StringBuffer buffer = new StringBuffer(get()); 

    try { 
     int counter = 0; 
     for (int i=0; i<length; i++) { 
      int slaveOffset = masterToSlaveMapping.get(offset+i); 
      if (slaveOffset != -1) { 
       buffer.deleteCharAt(slaveOffset - counter); 
       slaveToMasterMapping.remove(slaveOffset - counter); 
       counter++; 
      } 
     } 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 

    setSlaveOnly(buffer.toString()); 

    rebuildMasterToSlaveMapping(); 
} 

public void addMasterDocumentRange(int offset, int length) throws BadLocationException { 

    if (length == 0) { 
     return; 
    } 

    StringBuffer buffer = new StringBuffer(get()); 
    String masterString = masterDocument.get(); 

    try {  
     int counter = 0; 
     for (int i=0; i<length; i++) { 
      int slaveOffset = masterToSlaveMapping.get(offset+i); 
      if (slaveOffset == -1) { 
       int insertIndex = 0; 
       for (int j=offset+i; j>=0; j--) { 
        if (masterToSlaveMapping.get(j) != -1) { 
         insertIndex = masterToSlaveMapping.get(j)+1; 
         break; 
        } 
       } 
       buffer.insert(insertIndex + counter, masterString.charAt(offset + i)); 
       slaveToMasterMapping.add(insertIndex + counter, offset+i); 
       counter++; 
      } 
     } 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 

    setSlaveOnly(buffer.toString()); 

    rebuildMasterToSlaveMapping(); 
} 

public int toMasterOffset(int offset) throws BadLocationException { 
    try { 
     return slaveToMasterMapping.get(offset); 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 
} 

public int toSlaveOffset(int offset) throws BadLocationException { 
    try { 
     return masterToSlaveMapping.get(offset); 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 
} 

public IRegion toMasterRegion(int offset, int length) throws BadLocationException { 

    try { 
     if (length == 0) { 
      throw new BadLocationException(); 
     } 
     int[] master = new int[length]; 
     for (int i=0; i<length; i++) { 
      master[i] = slaveToMasterMapping.get(offset+i); 
      if (i > 0) { 
       if (master[i] != (master[i-1] + 1)) { 
        throw new BadLocationException(); 
       } 
      } 
     } 
     return new Region(master[0], master.length); 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 
} 

public IRegion toSlaveRegion(int offset, int length) throws BadLocationException { 

    try { 
     if (length == 0) { 
      throw new BadLocationException(); 
     } 
     int[] slave = new int[length]; 
     for (int i=0; i<length; i++) { 
      slave[i] = masterToSlaveMapping.get(offset+i); 
      if (i > 0) { 
       if (slave[i] != (slave[i-1] + 1)) { 
        throw new BadLocationException(); 
       } 
      } 
     } 
     return new Region(slave[0], slave.length); 
    } 
    catch (Exception e) { 
     throw new BadLocationException(); 
    } 
} 

@Override 
public void documentAboutToBeChanged(DocumentEvent event) { 
} 

@Override 
public void documentChanged(DocumentEvent event) { 
    setSlaveOnly(masterDocument.get()); 
} 

private void setSlaveOnly(String text) { 
    setMaster = false; 
    super.set(text); 
    setMaster = true; 
} 

private void replaceSlaveOnly(int pos, int length, String text) throws BadLocationException { 
    replaceMaster = false; 
    super.replace(pos, length, text); 
    replaceMaster = true; 
} 

private void rebuildMasterToSlaveMapping() { 

    int length = masterDocument.getLength(); 

    masterToSlaveMapping.clear(); 

    for (int i=0; i<length; i++) { 
     masterToSlaveMapping.add(-1); 
    } 
    for (int i=0; i<slaveToMasterMapping.size(); i++) { 
     int masterOffset = slaveToMasterMapping.get(i); 
     if (masterOffset != -1) { 
      masterToSlaveMapping.set(masterOffset, i); 
     } 
    } 
} 
} 
3

Google有一個雙向映射。

+0

感謝您的提示(我只知道Apache Commons的實現)。地圖的缺點是它不像列表(我需要)。如果我刪除一個鍵/索引,那麼我必須自己調整所有其他鍵。也不可能像列表一樣以有序的方式迭代它:-( – Zardoz 2009-12-25 14:07:11