2013-08-31 68 views
5

在幾種編程語言中,有Set集合,它們應該是有限集合的數學概念的實現。爲什麼許多編程語言中的集合不是真的集合?

然而,這未必是真實的,例如在C#JavaHashSet<T>兩種實現允許您添加任何HashSet<T>集合作爲自身的一個成員。不允許使用數學集的現代定義。

背景:

根據樸素集合論,一組的定義是:

一組是不同的對象的集合。

然而,這個定義導致着名的Russel's Paradox以及其他悖論。爲了方便起見,羅素的悖論是:

讓R是所有不屬於自己成員的集合。如果R 不是其自身的成員,則其定義指示它必須包含自身,並且如果它包含自身,則它與它自己的定義相矛盾,作爲不是其自身成員的所有集合的集合。

所以根據現代集理論(參見:ZFC),一組的定義是:

一組是不同的對象,其中沒有一個是集 本身的集合。

具體而言,這是axiom of regularity的結果。

那又如何?這有什麼影響?爲什麼這個問題在StackOverflow上?

羅素的矛盾之一是並非所有的集合都是集合。此外,這是數學家放棄定義作爲通常的英語定義的地步。所以我認爲這個問題在編程語言設計中有很大的影響力。

問題(S):

那麼,爲什麼編程語言,誰在某種形式,用這些原則在他們的設計非常只是忽略它設置在他們的語言庫的實現?其次,這是數學概念的其他實現常見的情況嗎?

也許我有點挑剔,但如果這些都是集合的真正實現,那麼爲什麼會忽略這個定義的一部分?

更新

的C#和Java代碼片斷示範行爲增加:

Java代碼:

Set<Object> hashSet = new HashSet<Object>(); 
hashSet.add(1); 
hashSet.add("Tiger"); 
hashSet.add(hashSet); 
hashSet.add('f'); 

Object[] array = hashSet.toArray(); 
HashSet<Object> hash = (HashSet<Object>)array[3]; 

System.out.println("HashSet in HashSet:");  
for (Object obj : hash) 
    System.out.println(obj); 

System.out.println("\nPrinciple HashSet:"); 
for (Object obj : hashSet) 
    System.out.println(obj); 

打印出:

HashSet in HashSet: 
f 
1 
Tiger 
[f, 1, Tiger, (this Collection)] 

Principle HashSet: 
f 
1 
Tiger 
[f, 1, Tiger, (this Collection)] 

C#代碼片段:

HashSet<object> hashSet = new HashSet<object>(); 
hashSet.Add(1); 
hashSet.Add("Tiger"); 
hashSet.Add(hashSet); 
hashSet.Add('f'); 

object[] array = hashSet.ToArray(); 
var hash = (HashSet<object>)array[2]; 

Console.WriteLine("HashSet in HashSet:"); 
foreach (object obj in hash) 
    Console.WriteLine(obj); 

Console.WriteLine("\nPrinciple HashSet:"); 
foreach (object obj in hashSet) 
    Console.WriteLine(obj); 

打印出:

HashSet in HashSet: 
1 
Tiger 
System.Collections.Generic.HashSet`1[System.Object] 
f 

Principle HashSet: 
1 
Tiger 
System.Collections.Generic.HashSet`1[System.Object] 
f 

更新2

在問候的Martijn Courteaux的第二點是它可以用計算效率的名義完成:

我在C#中做了兩個測試集合。它們是相同的,除了其中一個的Add方法 - 我添加了以下檢查:if (this != obj)其中obj是要添加到集合中的項目。

我主頻他們兩人分別在那裏他們增加的100,000個隨機整數:

通過Check:〜28毫秒

沒有檢查:〜21毫秒

這是一個性能跳躍相當顯着。

+3

您可能會驚訝地發現,計算機的數字概念並不包括康托爾的無限性。計算機是有限的;數學不是。 – stark

+0

「集合是不同對象的集合,它們都不是集合本身。」如果你的集合是S = HashSet ,你不能將它添加到HashSet中,因爲它的類型不是T.定義並不是說集合中的元素不能是集合,它只是說一個設置不能包含它自己。 – Save

+2

@Save A'Set '可以包含自己,因爲「Set 」是Object的子類型。只有在沒有子類型的語言中(或者更一般地說,在不同類型的「集合」沒有共同超類型的語言中),類型系統纔會阻止包含它們的集合。 – sepp2k

回答

9

編程語言集真的是不喜歡ZFC設置,但相當不同的理由比你想:

  1. 不能形成(即一套由修真集中的所有對象的等那......)。請注意,這已經阻止了所有(我相信)天真集理論悖論,所以它們是無關緊要的。

  2. 它們通常不能是無限的。

  3. 存在沒有設置的對象(在ZFC中有只有設置)。

  4. 它們通常是可變的(即您可以添加/刪除元素/從集合中)。

  5. 它們包含的對象可以是可變的。

所以答案

那麼,爲什麼編程語言,誰在某種形式,用這些原則在他們的設計非常只是忽略它設置在他們的語言庫的實現?

是語言不要使用這些原則。

+2

用#1輕微地嘲弄:你可以在現有集合*(我不知道Java/C#,但是像'set.filter(predicate)')這樣的所有對象的集合*,這反映了ZFC的理解公理(並因此阻止了矛盾)。但是,是的,編程語言不會直接發現在ZFC上。 –

+0

是的,好點。 –

+2

@ AntalS-Z,我相信對應於分離的公理(模式),而不是理解。 ZFC不允許(無限制)理解。 – ibid

0

在java中,該集合是數學集合。您可以插入對象,但只有一個可以在該組中。從約集的Javadoc信息:

「包含重複元素的集合更正式地,集包含沒有對E1元件和e2使得e1.equals(E2),和至多一個空元素爲。這個接口模擬數學集抽象。「

來源:http://docs.oracle.com/javase/7/docs/api/

3

我不能爲C#說話,但就如Java而言一套是一套。如果你看看the javadoc for the Set interface,你會看到(強調我的):

注意:如果可變對象用作set元素,必須非常小心。如果對象的值以影響等於比較的方式更改,而對象是集合中的元素,則不會指定集的行爲。 這種禁令的一個特例是不允許一個集合將其自身包含爲一個元素。

無論禁令積極執行不清楚(添加一個HashSet本身不會引發例如任何例外),但至少也有明確說明,你不應該嘗試,因爲該行爲將被指定。

+1

HashSet允許它,儘管文檔說它沒有。它甚至在'toString'方法中有一個特殊的子句,它使它成爲'(this set)',而不是進入無限遞歸。 – Ghostkeeper

+0

我用一些代碼片段更新了我的問題。正如@Ghostkeeper所說,似乎文檔沒有遵循。 –

+1

@DerekW該文檔規定了界面的合同,並規定如果您不遵循該合同,則行爲未明確。我不明白爲什麼沒有明確強制執行這個事實是一個問題:程序員有責任遵循管理他所使用的對象的規則。如果你不遵守規則,這在數學中是一樣的[你可以證明1 = 2](http://en.wikipedia.org/wiki/Mathematical_fallacy#All_numbers_equal_all_other_numbers)... – assylias

4

嗯,我認爲,這是因爲一些原因:

  1. 非常具體的編程目的,您可能希望創建一組包含本身。當你這樣做時,你並不真正關心數學上的設置,而只是想享受Set提供的功能:「將」元素添加到該設置而不創建重複條目。 (我必須誠實地說,我想不出你想要這樣做的情況。)

  2. 出於性能目的。你想使用Set並讓它包含自己的機會非常非常罕見。因此,如果計算能力,能量,時間,性能和環境健康狀況每次嘗試添加元素(如果它本身就是集合),就會造成浪費。

+0

點2有意義。 – assylias

+0

我對你的第二點做了一次性能比較(參見我更新的問題)。它可能是以表演的名義完成的。 –

相關問題