forked from tim-chow/DataStructure
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
周井江-技术中心-服务研发部
committed
Sep 1, 2017
1 parent
f6c55ed
commit 70d0840
Showing
3 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import java.util.*; | ||
|
||
class Node<T> { | ||
public static class Entry<T> { | ||
public Node<T> node; | ||
public int index; | ||
|
||
@Override | ||
public String toString() { | ||
String nodeString = "null"; | ||
if (node != null) | ||
nodeString = node.toString(); | ||
return String.format("Entry{node=%s, index=%d}", nodeString, index); | ||
} | ||
} | ||
|
||
private T element; | ||
private int parent; | ||
|
||
public Node(T element) { | ||
this(element, -1); | ||
} | ||
|
||
public Node(T element, int parent) { | ||
this.element = element; | ||
this.parent = parent; | ||
} | ||
|
||
|
||
public T getElement() { | ||
return element; | ||
} | ||
|
||
public int getParent() { | ||
return parent; | ||
} | ||
|
||
public void setParent(int parent) { | ||
this.parent = parent; | ||
} | ||
|
||
public Entry<T> findRoot(List<Node<T>> nodes) { | ||
Entry<T> entry = new Entry<>(); | ||
entry.index = nodes.indexOf(this); | ||
entry.node = this; | ||
|
||
Node<T> node = this; | ||
while (node.getParent() >= 0) { | ||
entry.index = node.getParent(); | ||
entry.node = node = nodes.get(entry.index); | ||
} | ||
return entry; | ||
} | ||
|
||
public void merge(Node<T> anotherNode, List<Node<T>> nodes) { | ||
Entry<T> anotherEntry = anotherNode.findRoot(nodes); | ||
Entry<T> entry = this.findRoot(nodes); | ||
if (anotherEntry.node == entry.node) | ||
return; | ||
|
||
int anotherCount = -1 * anotherEntry.node.getParent(); | ||
int count = -1 * entry.node.getParent(); | ||
|
||
if (anotherCount > count) { | ||
entry.node.setParent(anotherEntry.index); | ||
anotherEntry.node.setParent(-1*(anotherCount + count)); | ||
} else { | ||
anotherEntry.node.setParent(entry.index); | ||
entry.node.setParent(-1*(anotherCount + count)); | ||
} | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return String.format("Node{element=%s, parent=%d}", | ||
element.toString(), parent); | ||
} | ||
} | ||
|
||
public class MFSet { | ||
public static void main(String[] args) { | ||
List<Node<Integer>> nodes = new ArrayList<>(); | ||
for (int i = 0; i < 9; i++) | ||
nodes.add(new Node(i)); | ||
int[][] R = new int[][]{new int[]{0, 2}, new int[]{2, 4}, | ||
new int[]{4, 6}, new int[]{6, 8}}; | ||
|
||
for (int[] pair: R) { | ||
nodes.get(pair[0]).merge(nodes.get(pair[1]), nodes); | ||
} | ||
|
||
System.out.println(nodes); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
class Node: | ||
def __init__(self, element, parent=-1): | ||
self._element = element | ||
self._parent = parent | ||
|
||
def set_parent(self, parent): | ||
self._parent = parent | ||
|
||
def get_parent(self): | ||
return self._parent | ||
|
||
def get_element(self): | ||
return self._element | ||
|
||
def find_root(self, nodes): | ||
index = nodes.index(self) | ||
node = self | ||
while node.get_parent() >= 0: | ||
index = node.get_parent() | ||
node = nodes[index] | ||
return node, index | ||
|
||
def merge(self, another, nodes): | ||
another_root, another_index = another.find_root(nodes) | ||
root, index = self.find_root(nodes) | ||
if another_root == root: | ||
return | ||
|
||
another_nodes_count = -1 * another_root.get_parent() | ||
nodes_count = -1 * root.get_parent() | ||
|
||
if another_nodes_count > nodes_count: | ||
root.set_parent(another_index) | ||
another_root.set_parent(-1*(another_nodes_count + nodes_count)) | ||
else: | ||
another_root.set_parent(index) | ||
root.set_parent(-1*(another_nodes_count + nodes_count)) | ||
|
||
def __str__(self): | ||
return "Node[element={0._element}, parent={0._parent}]".format(self) | ||
__repr__ = __str__ | ||
|
||
def main(): | ||
R = [(0, 2), (2, 4), (4, 6), (6, 8)] | ||
S = [0, 1, 2, 3, 4, 5, 6, 7, 8] | ||
nodes = [Node(element, -1) for element in S] | ||
|
||
for x, y in R: | ||
nodes[x].merge(nodes[y], nodes) | ||
|
||
print nodes | ||
|
||
if __name__ == "__main__": | ||
main() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<h3>等价关系</h3> | ||
设R是非空集合S上的二元关系,如果R是<strong>自反的</strong>、<strong>对称的</strong>、<strong>传递的</strong>,则称R是S上的等价关系。</br> | ||
<ul> | ||
<li><strong>自反性</strong>:如果元素a属于集合S,则(a, a)属于R</br>∀ a ∈ S => (a, a) ∈ R</li> | ||
<li><strong>对称性</strong>:如果(a, b)属于R,且a不等于b,则(b, a)属于R</br>(a, b) ∈ R ∧ a ≠ b => (b, a) ∈ sR</li> | ||
<li><strong>传递性</strong>:如果(a, b)属于R,(b, c)属于R,则(a, c)属于R</br>(a, b) ∈ R, (b, c) ∈ R => (a, c) ∈ R</li> | ||
</ul> | ||
如果(a, b) ∈ R,则称a和b是等价的,记作 a ~ b。</br> | ||
比如,同班同学 和 同乡 是等价关系;相似三角形 和 全等三角形 是等价关系。。。 | ||
<hr></hr> | ||
<h3>树的双亲表示法</h3> | ||
用一个<em>链表</em>存储树的每一个结点;每个结点包含两个域:数据域---用来保存数据,指针域---用来指示双亲节点在链表中的索引。</br> | ||
因为根节点没有双亲节点,所以根节点的指针域的值是负的,可以利用这个负值来表示,树中节点的数量。</br> | ||
在双亲表示法中,便于寻找根节点 和 父节点。但是寻找子节点需要遍历所有节点。 | ||
<hr></hr> | ||
<h3>如何划分等价类</h3> | ||
按R将S划分成若干个不相交的子集S1,S2,。。。,Sn(它们的并集是S),则称这些子集是S的<strong>等价类</strong>。</br> | ||
假设集合S有n个元素,m个形如(x, y)(x, y ∈ S)的<strong>等价偶对</strong>确定了等价关系R。则将S划分成等价类的算法是:</br> | ||
<ul> | ||
<li>令集合S中的每个元素 各自 形成一个只包含单个结点的子集,记作S1,S2。。。Sn</li> | ||
<li>依次读入m个等价偶对,对于每一个偶对(x, y),设x属于S<sub>i</sub>,y属于S<sub>j</sub>,当S<sub>i</sub>不等于S<sub>j</sub>时,可以将S<sub>i</sub>合并到S<sub>j</sub>,并将S<sub>i</sub>置空(也可以将S<sub>j</sub>合并到S<sub>i</sub>,并将S<sub>j</sub>置空)</li> | ||
</ul> | ||
<strong><em>值得注意的是:在进行合并的时候,如果总是将节点多的树合并到节点少的树,会导致树的高度变大,进而导致 寻找节点所属的树的根节点的时候,时间会增大。</em>因此,在合并的时候,选择将节点少的树合并到节点多的树,并且利用根节点的游标域保存该棵树的节点数量的负值。</strong> |