Tôi thực sự thích google golang nhưng ai đó có thể giải thích lý do căn bản cho những người triển khai đã bỏ qua một cấu trúc dữ liệu cơ bản như các bộ từ thư viện chuẩn không?
Tôi thực sự thích google golang nhưng ai đó có thể giải thích lý do căn bản cho những người triển khai đã bỏ qua một cấu trúc dữ liệu cơ bản như các bộ từ thư viện chuẩn không?
Câu trả lời:
Một lý do tiềm năng cho sự thiếu sót này là việc mô hình hóa các bộ với bản đồ thực sự dễ dàng.
Thành thật mà nói tôi nghĩ đó là một chút quá sức, tuy nhiên nhìn vào Perl, câu chuyện hoàn toàn giống nhau. Trong Perl, bạn nhận được danh sách và hàm băm, trong Go bạn nhận được mảng, lát và bản đồ. Trong Perl, bạn thường sử dụng hàm băm cho bất kỳ và tất cả các vấn đề liên quan đến một bộ, điều tương tự cũng được áp dụng cho Go.
Thí dụ
để bắt chước một ints set trong Go, chúng tôi xác định bản đồ:
set := make(map[int]bool)
Để thêm một cái gì đó dễ dàng như:
i := valueToAdd()
set[i] = true
Xóa một cái gì đó chỉ là
delete(set, i)
Và sự vụng về tiềm năng của cấu trúc này dễ dàng bị trừu tượng hóa:
type IntSet struct {
set map[int]bool
}
func (set *IntSet) Add(i int) bool {
_, found := set.set[i]
set.set[i] = true
return !found //False if it existed already
}
Và xóa và nhận có thể được định nghĩa tương tự, tôi có thực hiện đầy đủ ở đây . Sự bất mãn lớn ở đây là thực tế là đi không có thuốc generic. Tuy nhiên, có thể làm điều này với interface{}
trường hợp bạn đã đưa ra kết quả nhận được.
map[int]bool
người ta có thể sử dụng map[int]struct{}
thay thế. Tôi thích cuối cùng.
map[int]struct{}
.. struct{}
Mất 0 byte.
map[int]struct{}
bạn không thể làm gì if mymap["key"] {
để kiểm tra tư cách thành viên. Google khuyên bạn nên sử dụngbool
(tìm kiếm "Có thể triển khai một bộ").
Tôi nghĩ rằng điều này phải làm với golang
sự tập trung vào sự đơn giản. set
s trở nên thực sự hữu ích với difference
, intersection
, union
, issubset
, và vân vân .. phương pháp. Có lẽ golang
nhóm cảm thấy rằng nó là quá nhiều cho một cấu trúc dữ liệu. Nhưng mặt khác, một "tập câm" chỉ có add
, contains
và remove
có thể dễ dàng nhân rộng với map
như được giải thích bởi @jozefg.
Câu trả lời trước chỉ hoạt động NẾU khóa là loại tích hợp. Để bổ sung cho câu trả lời trước, đây là một cách để thực hiện một tập hợp có các thành phần là các loại do người dùng xác định:
package math
// types
type IntPoint struct {
X, Y int
}
// set implementation for small number of items
type IntPointSet struct {
slice []IntPoint
}
// functions
func (p1 IntPoint) Equals(p2 IntPoint) bool {
return (p1.X == p2.X) && (p1.Y == p2.Y)
}
func (set *IntPointSet) Add(p IntPoint) {
if ! set.Contains(p) {
set.slice = append(set.slice, p)
}
}
func (set IntPointSet) Contains(p IntPoint) bool {
for _, v := range set.slice {
if v.Equals(p) {
return true
}
}
return false
}
func (set IntPointSet) NumElements() int {
return len(set.slice)
}
func NewIntPointSet() IntPointSet {
return IntPointSet{(make([]IntPoint, 0, 10))}
}
type mySet map[IntPoint]bool
hoạt động hoàn toàn tốt. Tất cả những gì được yêu cầu của loại khóa được sử dụng trong bản đồ là nó có ==
và!=
. Bình đẳng của các loại cấu trúc được xác định rõ, Equals
phương pháp của bạn nên công bằng p1 == p2
.
Contains
mất thời gian tuyến tính, trong khi aMap[]
mất thời gian không đổi, bất kể số lượng thành viên. Một giải pháp tốt hơn sẽ tạo ra một khóa duy nhất dựa trên nội dung của từng thành viên và tận dụng truy vấn thời gian liên tục mà map
loại cung cấp. Ngay cả các giải pháp nhanh hơn xem xét hành vi bộ đệm, vv cũng tồn tại.