Go數據結構之集合

1、什麼是集合

集合就是不一樣對象的無序彙集。那麼鏈表和集合有什麼關係呢?咱們來變個魔術。以下圖是各類顏色組成的鏈表:
%E9%9B%86%E5%90%88%E9%93%BE%E8%A1%A81.pnggit

下面咱們一步步把鏈表變成集合。
第一步砍去連接
%E9%9B%86%E5%90%88%E9%93%BE%E8%A1%A82.pnggithub

第二步去掉重複
%E9%9B%86%E5%90%88%E9%93%BE%E8%A1%A83.png算法

第三步放到一個框裏搖一搖就成集合了
%E9%9B%86%E5%90%88%E9%93%BE%E8%A1%A84.png數據結構

能夠看出集合有這些特色:數據結構和算法

  • 無序:鏈表去掉連接,就是去掉元素間有序狀態。
  • 不重複:去掉重複的玫紅色。

雖說集合是一種數學概念,但在實際生活中無處不透露着集合。好比一個班級的學生是一個集合。班級裏的男生又是一個集合。函數

2、集合的結構

%E9%9B%86%E5%90%88%E9%93%BE%E8%A1%A85.png

大衛哥這裏爲了簡化概念的描述,繼續用單鏈表來表示集合,可是在對集合作計算的時候單鏈表並不合適,數據量大的時候它的弊端就會顯現,在講到後面的數據結構和算法的時候,咱們再回頭來完善前面講的數據接口的實現。學習

3、接口說明及實現

圖片描述

一、Init

初始化集合,本質是初始化鏈表。優化

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

二、Insert

把元素放入集合中。spa

func (set *Set) Insert(data Object) bool {
    if (!set.IsMember(data)) {
        return (*set).list.Append(data)
    }
    
    return false
}

三、IsEmpty

是不是空集合。

func (set *Set) IsMember(data Object) bool {
    return (*set).list.IsMember(data);
}

四、IsMember

是不是集合元素。

func (set *Set) IsMember(data Object) bool {
    return (*set).list.IsMember(data);
}

五、Remove

刪除指定集合元素。

func (set *Set) Remove(data Object) bool {
    return (*set).list.Remove(data)
}

六、Union

並集計算。

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的並集。

七、InterSection

計算交集。

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
}

八、Difference

計算差集。

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的集合。

九、IsSubSet

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的子集。

十、Equals

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中集合元素是否同樣。

十一、訪問集合元素

由於集合是沒有順序的,因此無法用序號來訪問集合元素(雖然這裏是用單鏈表實現)。這裏咱們用迭代器的方式來實現元素的訪問。首先咱們定義一個迭代器的接口。

(1) Iterator

type Iterator interface{
    HasNext() bool
    Next() Object
}

(2) SetIterator

type SetIterator struct {
    index uint64
    set *Set
}

由於Iterator是接口,無法保存狀態,因此咱們得定義一個類型來保存每次訪問的遊標。這裏的遊標是序號。

(3) GetIterator

返回一個實現了Iterator接口的對象。

func (set *Set) GetIterator() *SetIterator {
    iterator := new(SetIterator)
    (*iterator).index = 0
    (*iterator).set = set

    return iterator
}

(4) HasNext

是否有其餘元素沒訪問到?

func (iterator *SetIterator) HasNext() bool {
    set := (*iterator).set
    index := (*iterator).index

    return (index < set.getSize())
}

這是Iterator中HasNext方法的實現。

(5) Next

獲取其餘元素。

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
}

4、小結

集合在機率中有不少應用,這裏咱們僅僅是用單鏈表簡單的實現了集合,在大量數據下,計算效率很低。隨着學習的深刻,咱們會優化這些數據接口的實現。
代碼下載

相關文章
相關標籤/搜索