Golang理解-集合


集合


Go語言里的集合一般會用map[T]bool這種形式來表示,T代表元素類型。
集合用map類型來表示雖然非常靈活,但我們可以以一種更好的形式來表示它。例如:在數據流分析領域,集合元素通常是一個非負整數,集合會包含很多元素,並且集合會經常進行並集、交集操作,這種情況下,bit數組會比map表現更加理想

我們知道在go語言中,出了幾本數據類型外; 還有slice,map,struct,interface這些復雜數據類型;
但是我們發現在go中好像沒有集合(set)這種數據類型,那么我們該如何通過go的基礎類型和復雜數據類型來實現集合呢?
下面看一個int類型集合的實現

type IntSet struct {
    words []uint64
}

func (s *IntSet) Has(x int) bool {
    word, bit := x/64, uint(x%64)
    return word < len(s.words) && s.words[word]&(1<<bit) != 0
}

func (s *IntSet) Add(x int) {
    word, bit := x/64 ,uint(x%64)
    for word >= len(s.words) {
        s.words = append(s.words, 0)
    }
    s.words[word] |= 1 << bit
}

func (s *IntSet) UnionWith(t *IntSet) {
    for i, tword := range t.words {
        if i < len(s.words) {
            s.words[i] |= tword
        } else {
            s.words = append(s.words, tword)
        }
    }
}

func (s *IntSet) String() string {
    var buf bytes.Buffer
    buf.WriteByte('{')
    for i, word := range s.words {
        if word == 0 {
            continue
        }
        for j := 0; j < 64; j++ {
            if word&(1 << uint(j)) != 0 {
                if buf.Len() > len("{") {
                    buf.WriteByte(' ')
                }
                fmt.Fprintf(&buf, "%d", 64 * i + j)
            }
        }
    }
    buf.WriteByte('}')
    return buf.String()
}

方法


上面的代碼定義了一個IntSet的結構體,結構體中的字段是一個[]int64的切片,用於存儲int64類型的整型數據;
func (s *IntSet) Has(x int) bool 為IntSet結構體提供了一個方法,用於判斷集合內是否有某個元素了;
func (s *IntSet) Add(x int) 為IntSet結構體提供了添加元素的方法;
func (s *IntSet) UnionWith(t *IntSet) 為IntSet結構體提供了一個方法,用於將2個IntSet類型的集合做並集;

設計思路


一個bit數組通常會用一個無符號數或者稱之為“字”的slice來表示,每一個元素的每一位都表示集合里的一個值。當集合的第i位被設置時,我們才說這個集合包含元素i
因為每一個字都有64個二進制位,所以為了定位x的bit位,我們用了x/64的商作為字的下標,並且用x%64得到的值作為這個字內的bit的所在位置。
UnionWith這個方法里用到了bit位的“或”邏輯操作符號|來一次完成64個元素的或計算


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM