集合就是不一樣對象的無序彙集。那麼鏈表和集合有什麼關係呢?咱們來變個魔術。以下圖是各類顏色組成的鏈表:
git
下面咱們一步步把鏈表變成集合。
第一步砍去連接
github
第二步去掉重複
算法
第三步放到一個框裏搖一搖就成集合了
數據結構
能夠看出集合有這些特色:數據結構和算法
雖說集合是一種數學概念,但在實際生活中無處不透露着集合。好比一個班級的學生是一個集合。班級裏的男生又是一個集合。函數
大衛哥這裏爲了簡化概念的描述,繼續用單鏈表來表示集合,可是在對集合作計算的時候單鏈表並不合適,數據量大的時候它的弊端就會顯現,在講到後面的數據結構和算法的時候,咱們再回頭來完善前面講的數據接口的實現。學習
初始化集合,本質是初始化鏈表。優化
func (set *Set) Init(match ...MatchFun) { lst := new(List) (*set).list = lst if len(match) == 0 { lst.Init() } else { lst.Init(match[0]) } }
要比較集合中的元素,咱們得傳入一個比較函數,這裏的match是咱們的自定義類型MatchFun,你們能夠查看代碼裏的定義。ui
把元素放入集合中。spa
func (set *Set) Insert(data Object) bool { if (!set.IsMember(data)) { return (*set).list.Append(data) } return false }
是不是空集合。
func (set *Set) IsMember(data Object) bool { return (*set).list.IsMember(data); }
是不是集合元素。
func (set *Set) IsMember(data Object) bool { return (*set).list.IsMember(data); }
刪除指定集合元素。
func (set *Set) Remove(data Object) bool { return (*set).list.Remove(data) }
並集計算。
func (set *Set) Union(set1 *Set) *Set { if (set1 == nil) { return nil } nSet := new(Set) nSet.Init((*((*set).list)).myMatch) if (set.IsEmpty() && set1.IsEmpty()) { return nSet } for i := uint64(0); i < set.getSize(); i++ { nSet.Insert(set.getAt(i)) } var data Object for i := uint64(0); i < set1.getSize(); i++ { data = set1.getAt(i) if (!nSet.IsMember(data)) { nSet.Insert(data) } } return nSet }
計算set和set1的並集。
計算交集。
func (set *Set) InterSection(set1 *Set) *Set { if (set1 == nil) { return nil } nSet := new(Set) nSet.Init((*((*set).list)).myMatch) if (set.IsEmpty() || set1.IsEmpty()) { return nSet } fSet := set sSet := set1 lenth := set.getSize() if (set1.getSize() < lenth) { fSet = set1 sSet = set } var data Object for i := uint64(0) ; i < lenth; i++ { data = fSet.getAt(i) if (sSet.IsMember(data)) { nSet.Insert(data) } } return nSet }
計算差集。
func (set *Set) Difference(set1 *Set) *Set { if (set1 == nil) { return nil } nSet := new(Set) nSet.Init((*((*set).list)).myMatch) if (set.IsEmpty()) { return nSet } var data Object for i := uint64(0); i < set.getSize(); i++ { data = set.getAt(i) if (!set1.IsMember(data)) { nSet.Insert(data) } } return nSet }
返回的集合是屬於set,但不屬於set1的集合。
func (set *Set) IsSubSet(subSet *Set) bool { if (set == nil) { return false } if (subSet == nil) { return true } for i := uint64(0); i < subSet.getSize(); i++ { if (!(set.IsMember(subSet.getAt(i)))) { return false } } return true }
確認subSet是不是set的子集。
func (set *Set) Equals(set1 *Set) bool { if (set == nil || set1 == nil) { return false } if (set.IsEmpty() && set1.IsEmpty()) { return true } nSet := set.InterSection(set1) return (set.getSize() == nSet.getSize()) }
判斷set和set1中集合元素是否同樣。
由於集合是沒有順序的,因此無法用序號來訪問集合元素(雖然這裏是用單鏈表實現)。這裏咱們用迭代器的方式來實現元素的訪問。首先咱們定義一個迭代器的接口。
type Iterator interface{ HasNext() bool Next() Object }
type SetIterator struct { index uint64 set *Set }
由於Iterator是接口,無法保存狀態,因此咱們得定義一個類型來保存每次訪問的遊標。這裏的遊標是序號。
返回一個實現了Iterator接口的對象。
func (set *Set) GetIterator() *SetIterator { iterator := new(SetIterator) (*iterator).index = 0 (*iterator).set = set return iterator }
是否有其餘元素沒訪問到?
func (iterator *SetIterator) HasNext() bool { set := (*iterator).set index := (*iterator).index return (index < set.getSize()) }
這是Iterator中HasNext方法的實現。
獲取其餘元素。
func (iterator *SetIterator) Next() Object { set := (*iterator).set index := (*iterator).index if (index < set.getSize()) { data := set.getAt(index) (*iterator).index++ return data } return nil }
集合在機率中有不少應用,這裏咱們僅僅是用單鏈表簡單的實現了集合,在大量數據下,計算效率很低。隨着學習的深刻,咱們會優化這些數據接口的實現。
代碼下載