LiSheng's blog LiSheng's blog
首页
笔记
个人简历
随笔集
GitHub (opens new window)
首页
笔记
个人简历
随笔集
GitHub (opens new window)
  • golang

  • cplus

    • 内存相关

      • new、delete、malloc、free
      • 智能指针
      • 内存池
    • 面向对象

    • STL相关

    • 内置数据结构
    • 数据结构示例
    • go和c++对比
      • Go的切片和c++ vector的对比
        • 相同点:
        • 不同点:
        • 总结:
      • Go中的容器 vs c++ 的容器
        • 1. Array 和 Slice(与 C++ 中的 `vector` 对应):
        • 2. Map(与 C++ 中的 `map` 和 `unordered_map` 对应):
        • 3. Stack(栈):
        • 4. Queue(队列):
        • 5. Deque(双端队列):
        • 6. Set(集合):
        • 7. Priority Queue(优先队列):
        • 8. Third-Party Libraries:
        • 总结:
    • 关键字

  • leetcode

  • 存储技术

  • 分布式系统

  • 计算机网络

  • Linux操作系统

  • Redis

  • 其他

  • 笔记
  • cplus
lisheng
2024-09-12
目录

go和c++对比

# Go的切片和c++ vector的对比

# 相同点:

  1. 动态大小:

    • Golang 切片 和 C++ vector 都可以根据需要动态调整大小。用户不需要手动管理它们的大小或容量,它们会自动进行扩容。
  2. 连续的内存:

    • 它们的底层存储都是基于连续的内存空间,这使得它们可以高效地进行随机访问。访问任意索引的元素的时间复杂度都是 O(1)。
  3. 自动扩容:

    • 当切片或 vector 容量不足时,都会自动扩容,将原有的元素复制到更大的内存块中。
    • 在大多数实现中,扩容通常会按照倍数增长的策略来减少频繁的重新分配。
  4. 基于引用的拷贝:

    • 在大多数情况下,切片和 vector 的拷贝都是浅拷贝,即传递的是底层数据的引用。更改副本中的内容会影响原始数据,除非显式进行深拷贝。

# 不同点:

  1. 底层数据结构:

    • Golang 切片:切片是对底层数组的引用。一个切片由三个部分组成:指向数组的指针、长度 和 容量。切片是对底层数组的视图,可以基于现有数组创建不同的切片,不需要重新分配内存。这也意味着多个切片可以共享同一个底层数组。
    • C++ vector:vector 本身是一个包含元素的容器,所有元素存储在 vector 自己管理的连续内存区域中。vector 中的元素不与其他容器共享内存。
  2. 容量管理:

    • Golang 切片:切片的容量是从其起始位置到底层数组末尾的空间。通过调整切片的长度,可以在不重新分配内存的情况下缩小或扩展切片的视图。当容量不足时,切片会自动分配新的底层数组。
    • C++ vector:vector 的容量和长度是独立的概念,vector 的容量是它当前能够容纳的元素数,长度是已存储的元素数。当 vector 的容量不足时,会进行扩容,分配新的内存块并复制原有数据。
  3. 多切片共享数据:

    • Golang 切片:由于切片是数组的视图,可以从同一个数组创建多个切片,这些切片共享同一个底层数组。修改一个切片可能会影响其他切片,除非显式地重新分配内存。
    • C++ vector:vector 的数据不共享,不可能通过多个 vector 直接共享同一块内存空间。每个 vector 独立管理它的内存。
  4. 内存管理与回收:

    • Golang 切片:切片在 Go 语言中依赖垃圾回收机制。只要切片或底层数组的引用还存在,垃圾回收器就不会释放底层数组的内存。当切片缩小时,切片的容量不会立即减少,因此可能会浪费一些未使用的内存,除非显式调用 copy 等方式将数据迁移到新数组中。
    • C++ vector:vector 由 C++ 的内存分配器管理。当 vector 被销毁或超出作用域时,内存会被立即释放。C++ 不需要垃圾回收。
  5. 线程安全:

    • Golang 切片:切片本身不是线程安全的,如果多个 goroutine 并发地修改切片,必须手动进行同步处理。
    • C++ vector:同样,vector 也不是线程安全的,多个线程同时访问或修改同一个 vector 也需要同步处理。
  6. API 风格:

    • Golang 切片:切片的 API 比 vector 更简单,比如通过内置函数 append 来动态增加元素。
    • C++ vector:提供了更丰富的操作接口,比如 insert、erase 等,用于在中间位置插入或删除元素,但操作相对繁琐。

# 总结:

  • 相同点:Golang 的切片和 C++ 的 vector 都是动态数组,提供连续内存存储、高效随机访问、自动扩容等功能。
  • 不同点:Golang 的切片是对底层数组的视图,可能与其他切片共享同一块内存,而 C++ 的 vector 是一个独立的容器,独占其内存。切片依赖垃圾回收进行内存管理,而 vector 由 C++ 的内存管理器负责,且 API 风格和内存分配方式有所不同。

# Go中的容器 vs c++ 的容器

在 Go 语言中,确实没有像 C++ 那样直接提供类似 stack、deque、unordered_map 等标准容器数据结构。Go 语言的设计哲学是简洁和直接,许多复杂的数据结构需要开发者自己实现或通过第三方库来使用。下面详细解释 Go 语言内置的数据结构和与 C++ 容器的对比:

# 1. Array 和 Slice(与 C++ 中的 vector 对应):

  • Array:Go 中的数组是固定大小的,与 C++ 的原生数组类似,大小是编译时确定的,且长度不可修改。
  • Slice:Go 中的 slice 是动态数组,可以随着元素的增加动态扩容。它与 C++ 中的 vector 类似,但 Go 的 slice 更简洁,同时具有 len 和 cap 概念,动态调整时可能会重新分配底层数组。

# 2. Map(与 C++ 中的 map 和 unordered_map 对应):

  • Map:Go 提供了内置的 map 类型,它实现了键值对的存储。Go 的 map 相当于 C++ 的 unordered_map,底层通过哈希表实现,因此查找、插入、删除的时间复杂度为 O(1)。
  • Go 没有像 C++ 的 map(基于红黑树,支持有序键值对)那样的有序映射容器。要实现有序的 map 需要自己管理键的顺序,比如可以在 map 之外维护一个排序的键数组。

# 3. Stack(栈):

  • Go 语言没有直接提供栈(stack)数据结构。栈的实现通常通过 slice 来完成。由于 slice 支持动态扩展,可以使用 append 添加元素,使用 len(slice)-1 来访问栈顶元素并通过 slice = slice[:len(slice)-1] 弹出栈顶元素。
  • 虽然没有标准库实现,但 slice 本质上可以轻松实现 LIFO(Last In, First Out)行为。
stack := []int{}
stack = append(stack, 10)  // Push
top := stack[len(stack)-1] // Peek
stack = stack[:len(stack)-1] // Pop
1
2
3
4

# 4. Queue(队列):

  • 类似于栈,Go 中没有内置的 queue 数据结构,但可以通过 slice 来实现。slice 支持从末尾插入和删除,但从头部删除时效率较低,因为需要移动所有元素。
  • 如果需要高效的双端队列操作,可以通过 slice 实现,也可以使用第三方库(比如 container/list)。
queue := []int{}
queue = append(queue, 10) // Enqueue
front := queue[0]         // Peek
queue = queue[1:]         // Dequeue
1
2
3
4

# 5. Deque(双端队列):

  • Go 没有内置的 deque 数据结构。虽然可以使用 slice 来模拟双端队列的功能,但由于 slice 在头部插入或删除元素需要移动其他元素,效率不是最优。
  • Go 提供了 container/list 包,可以实现双端队列的功能。list 是一个双向链表,支持从前面和后面高效地插入和删除元素。
import "container/list"

deque := list.New()
deque.PushBack(1)   // Append to the back
deque.PushFront(2)  // Append to the front
deque.Remove(deque.Back()) // Remove from the back
1
2
3
4
5
6

# 6. Set(集合):

  • Go 中没有直接的 set 数据结构,但可以通过 map 来模拟集合的行为,键作为元素,值可以设为 bool 类型的 true 或其他常量。
  • 这种实现方式非常高效,因为 Go 的 map 是基于哈希表实现的,查找、插入和删除的时间复杂度是 O(1)。
set := make(map[int]bool)
set[1] = true   // Add
delete(set, 1)  // Remove
exists := set[1] // Check existence
1
2
3
4

# 7. Priority Queue(优先队列):

  • Go 没有内置的优先队列(priority_queue)数据结构,但可以使用 container/heap 包来实现堆,进而构建优先队列。开发者需要实现一个满足 heap.Interface 接口的自定义类型,定义元素的排序规则。
  • heap 可以实现最小堆或最大堆,支持插入、删除和调整堆的操作。
import "container/heap"

// Define a priority queue by implementing heap.Interface
type IntHeap []int
func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
    *h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

func main() {
    h := &IntHeap{2, 1, 5}
    heap.Init(h)
    heap.Push(h, 3)
    fmt.Printf("minimum: %d\n", (*h)[0])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 8. Third-Party Libraries:

虽然 Go 没有像 C++ 那样提供丰富的标准容器库,但 Go 生态中有很多第三方库提供这些数据结构的实现,例如:

  • github.com/golang-collections/collections:提供类似于 stack、queue 和 deque 的实现。
  • github.com/emirpasic/gods:提供多种数据结构,包括 TreeMap、HashSet、PriorityQueue 等。

# 总结:

  • Golang 内置的数据结构 相对简洁,主要包括 slice、map 和 array,这些容器可以满足大部分应用场景。
  • C++ 提供了更为丰富和复杂的数据结构(如 stack、deque、unordered_map 等),这些容器封装得更完善,提供了更多的功能。
  • Go 鼓励开发者通过基础的内置数据结构(如 slice 和 map)构建自己需要的复杂数据结构,或依赖第三方库来扩展语言的功能。
编辑 (opens new window)
上次更新: 2024/09/13, 11:59:12
数据结构示例
static

← 数据结构示例 static→

最近更新
01
ceph分布式存储-对象存储(RGW)搭建
10-27
02
ceph分布式存储-集群客户端连接
10-27
03
ceph分布式存储-管理crushmap
10-27
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式