2025-03-25-01
This commit is contained in:
10
技术/Go/GC.md
Normal file
10
技术/Go/GC.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## Golang在GC的演进过程中也经历了很多次变革,Go V1.3之前的[标记-清除](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E6%A0%87%E8%AE%B0-%E6%B8%85%E9%99%A4&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLmoIforrAt5riF6ZmkIiwiemhpZGFfc291cmNlIjoiZW50aXR5IiwiY29udGVudF9pZCI6MjM4MTU4MjU5LCJjb250ZW50X3R5cGUiOiJBcnRpY2xlIiwibWF0Y2hfb3JkZXIiOjEsInpkX3Rva2VuIjpudWxsfQ.L519Jm1YZEEQ1wuzajxX2OOBhbTH7DbPZHy8nn6Obns&zhida_source=entity)(mark and sweep)算法。Go V1.3之前的标记-清扫(mark and sweep)的缺点。
|
||||
|
||||
大家可以重点关注以下版本的变化:
|
||||
|
||||
- Go V1.5的[三色并发标记法](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E4%B8%89%E8%89%B2%E5%B9%B6%E5%8F%91%E6%A0%87%E8%AE%B0%E6%B3%95&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLkuInoibLlubblj5HmoIforrDms5UiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.uWrIm2OB1_oK7lijlD4chkrpuqwtlbJ3MTtVKVst36c&zhida_source=entity)
|
||||
- Go V1.5的三色标记为什么需要STW
|
||||
- Go V1.5的三色标记为什么需要[屏障机制](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E5%B1%8F%E9%9A%9C%E6%9C%BA%E5%88%B6&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLlsY_pmpzmnLrliLYiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.z_KFIcdz9agqmRw6oF9lyMLd_pCuwW8t9F3iG5Rf264&zhida_source=entity)(“强-弱” 三色不变式、插入屏障、删除屏障 )
|
||||
- Go V1.8[混合写屏障](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E6%B7%B7%E5%90%88%E5%86%99%E5%B1%8F%E9%9A%9C&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLmt7flkIjlhpnlsY_pmpwiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.bbCbV48D0n6tpBTp3s-Ia-MV3I-tnPAEhS6Bg1JVFog&zhida_source=entity)机制
|
||||
- Go V1.8混合写屏障机制的全场景分析
|
||||
|
183
技术/Go/Go实现BitMap.md
Normal file
183
技术/Go/Go实现BitMap.md
Normal file
@@ -0,0 +1,183 @@
|
||||
在 Go 语言中,`uint64` 是一种无符号整数类型,占用 64 位(bit)。每一位可以存储一个布尔值(0 或 1)。以下是 `bit` 和 `uint64` 之间的对应关系及操作的详细解释:
|
||||
|
||||
---
|
||||
|
||||
### 1. **`uint64` 的结构**
|
||||
- 一个 `uint64` 类型的变量由 64 个二进制位组成,例如:
|
||||
```
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
```
|
||||
每一位从右到左编号为 0 到 63(最低位是第 0 位,最高位是第 63 位)。
|
||||
|
||||
---
|
||||
|
||||
### 2. **如何定位某个位**
|
||||
假设我们要操作第 `pos` 位(从 0 开始计数),可以通过以下步骤确定其在 `uint64` 中的位置:
|
||||
|
||||
#### (1) **计算所在 `uint64` 的索引**
|
||||
- 如果位图使用多个 `uint64` 来存储数据,则需要先确定目标位所在的 `uint64` 索引。
|
||||
- 公式为:
|
||||
```go
|
||||
index = pos / 64
|
||||
```
|
||||
- `pos / 64` 表示将位的位置除以 64,得到它属于哪个 `uint64`。
|
||||
|
||||
#### (2) **计算具体位偏移量**
|
||||
- 在确定了目标 `uint64` 后,需要进一步确定该位在当前 `uint64` 中的具体位置。
|
||||
- 公式为:
|
||||
```go
|
||||
offset = pos % 64
|
||||
```
|
||||
- `pos % 64` 表示取余运算,得到目标位在当前 `uint64` 中的偏移量(范围为 0 到 63)。
|
||||
|
||||
---
|
||||
|
||||
### 3. **位操作的实现**
|
||||
Go 语言提供了位运算符来操作单个位。以下是常见的位操作及其作用:
|
||||
|
||||
#### (1) **设置某一位为 1**
|
||||
- 使用按位或运算符 `|` 和左移运算符 `<<`:
|
||||
```go
|
||||
b.bits[pos/64] |= 1 << uint(pos%64)
|
||||
```
|
||||
- `1 << uint(pos%64)`:将数字 `1` 左移 `offset` 位,生成一个只有目标位为 1 的掩码。
|
||||
- `|=`:将掩码与当前 `uint64` 值进行按位或运算,确保目标位被设置为 1。
|
||||
|
||||
#### (2) **清除某一位为 0**
|
||||
- 使用按位与运算符 `&` 和按位取反运算符 `^`:
|
||||
```go
|
||||
b.bits[pos/64] &^= 1 << uint(pos%64)
|
||||
```
|
||||
- `1 << uint(pos%64)`:生成一个只有目标位为 1 的掩码。
|
||||
- `&^=`:将掩码取反后与当前 `uint64` 值进行按位与运算,确保目标位被清除为 0。
|
||||
|
||||
#### (3) **检查某一位是否为 1**
|
||||
- 使用按位与运算符 `&`:
|
||||
```go
|
||||
return b.bits[pos/64]&(1<<uint(pos%64)) != 0
|
||||
```
|
||||
- `1 << uint(pos%64)`:生成一个只有目标位为 1 的掩码。
|
||||
- `&`:将掩码与当前 `uint64` 值进行按位与运算,结果非零表示目标位为 1,否则为 0。
|
||||
|
||||
---
|
||||
|
||||
### 4. **举例说明**
|
||||
假设我们有一个 `uint64`,初始值为 `0`:
|
||||
```
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
```
|
||||
|
||||
#### (1) 设置第 10 位为 1
|
||||
- 计算索引和偏移量:
|
||||
- `index = 10 / 64 = 0`
|
||||
- `offset = 10 % 64 = 10`
|
||||
- 执行操作:
|
||||
```go
|
||||
bits[0] |= 1 << 10
|
||||
```
|
||||
结果:
|
||||
```
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000100 00000000
|
||||
```
|
||||
|
||||
#### (2) 清除第 10 位为 0
|
||||
- 执行操作:
|
||||
```go
|
||||
bits[0] &^= 1 << 10
|
||||
```
|
||||
结果:
|
||||
```
|
||||
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
```
|
||||
|
||||
#### (3) 检查第 10 位是否为 1
|
||||
- 执行操作:
|
||||
```go
|
||||
result := bits[0]&(1<<10) != 0
|
||||
```
|
||||
- 如果第 10 位为 1,`result` 为 `true`。
|
||||
- 如果第 10 位为 0,`result` 为 `false`。
|
||||
|
||||
---
|
||||
|
||||
### 5. **总结**
|
||||
- `uint64` 是一个 64 位的存储单元,每一位可以独立存储一个布尔值。
|
||||
- 通过 `pos / 64` 确定目标位所在的 `uint64`,通过 `pos % 64` 确定目标位在当前 `uint64` 中的具体位置。
|
||||
- 使用位运算符(如 `|`、`&`、`^` 和 `<<`)可以高效地操作单个位。
|
||||
|
||||
## 6.代码实现
|
||||
~~~ go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Bitmap 结构体表示位图
|
||||
type Bitmap struct {
|
||||
bits []uint64 // 使用一个 uint64 切片存储位图数据,每个元素存储 64 位
|
||||
size int // 位图的总大小(位数)
|
||||
}
|
||||
|
||||
// NewBitmap 创建一个新的位图,size为位图的大小
|
||||
func NewBitmap(size int) *Bitmap {
|
||||
if size < 0 {
|
||||
size = 0
|
||||
}
|
||||
return &Bitmap{
|
||||
bits: make([]uint64, (size+63)/64), // 根据位图大小计算需要的 uint64 元素数量
|
||||
size: size, // 记录位图的总大小
|
||||
}
|
||||
}
|
||||
|
||||
// SetBit 设置指定位置的位为1
|
||||
func (b *Bitmap) SetBit(pos int) {
|
||||
if pos < 0 || pos >= b.size { // 检查位置是否越界
|
||||
return
|
||||
}
|
||||
idx := pos / 64
|
||||
offset := pos % 64
|
||||
// 使用 uint64(1) 避免可能的整数溢出问题
|
||||
b.bits[idx] |= uint64(1) << offset
|
||||
}
|
||||
|
||||
// ClearBit 清除指定位置的位为0
|
||||
func (b *Bitmap) ClearBit(pos int) {
|
||||
if pos < 0 || pos >= b.size { // 检查位置是否越界
|
||||
return
|
||||
}
|
||||
idx := pos / 64
|
||||
offset := pos % 64
|
||||
// 使用 uint64(1) 避免可能的整数溢出问题
|
||||
b.bits[idx] &^= uint64(1) << offset
|
||||
}
|
||||
|
||||
// GetBit 获取指定位置的位
|
||||
func (b *Bitmap) GetBit(pos int) bool {
|
||||
if pos < 0 || pos >= b.size { // 检查位置是否越界
|
||||
return false
|
||||
}
|
||||
idx := pos / 64
|
||||
offset := pos % 64
|
||||
// 使用 uint64(1) 避免可能的整数溢出问题
|
||||
return (b.bits[idx] & (uint64(1) << offset)) != 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建一个大小为 100 的位图
|
||||
bitmap := NewBitmap(100)
|
||||
|
||||
// 设置第 10 位为 1
|
||||
bitmap.SetBit(10)
|
||||
|
||||
// 检查第 10 位是否为 1,并打印结果(输出 true)
|
||||
fmt.Println(bitmap.GetBit(10)) // 输出: true
|
||||
|
||||
// 清除第 10 位为 0
|
||||
bitmap.ClearBit(10)
|
||||
|
||||
// 再次检查第 10 位是否为 1,并打印结果(输出 false)
|
||||
fmt.Println(bitmap.GetBit(10)) // 输出: false
|
||||
}
|
||||
|
||||
~~~
|
@@ -3,6 +3,55 @@
|
||||
2^x = 1 << x
|
||||
x/2 x >> 1
|
||||
~~~
|
||||
|
||||
|
||||
## 递增的三元子序列
|
||||
给你一个整数数组 `nums` ,判断这个数组中是否存在长度为 `3` 的递增子序列。
|
||||
|
||||
如果存在这样的三元组下标 `(i, j, k)` 且满足 `i < j < k` ,使得 `nums[i] < nums[j] < nums[k]` ,返回 `true` ;否则,返回 `false` 。
|
||||
~~~ go
|
||||
func increasingTriplet(nums []int) bool {
|
||||
n := len(nums)
|
||||
if n < 3 {
|
||||
return false
|
||||
}
|
||||
first, sencond := nums[0], math.MaxInt32
|
||||
for i := 1;i < n;i++ {
|
||||
num := nums[i]
|
||||
if num > sencond {
|
||||
return true
|
||||
} else if num > first {
|
||||
sencond = num
|
||||
} else {
|
||||
first = num
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
~~~
|
||||
赋初始值的时候,已经满足second > first了,现在找第三个数third
|
||||
(1) 如果third比second大,那就是找到了,直接返回true
|
||||
(2) 如果third比second小,但是比first大,那就把second指向third,然后继续遍历找third
|
||||
(3) 如果third比first还小,那就把first指向third,然后继续遍历找third(这样的话first会跑到second的后边,但是不要紧,因为在second的前边,老first还是满足的)
|
||||
## 字符串的最大公因子
|
||||
~~~ go
|
||||
func gcdOfStrings(str1 string, str2 string) string {
|
||||
if str1+str2 != str2+str1 {
|
||||
return ""
|
||||
}
|
||||
return str1[:gcd(len(str1), len(str2))]
|
||||
}
|
||||
|
||||
// 欧几里得法求最大公因数
|
||||
func gcd(a, b int) int {
|
||||
if b == 0 {
|
||||
return a
|
||||
}
|
||||
return gcd(b, a%b)
|
||||
}
|
||||
~~~
|
||||
|
||||
|
||||
## 快乐数
|
||||
~~~ go
|
||||
func isHappy(n int) bool {
|
||||
@@ -424,7 +473,7 @@ func addStrings(num1 string, num2 string) string {
|
||||
for i, j := len(num1)-1, len(num2)-1; j >= 0 || i >= 0; {
|
||||
num := add
|
||||
if i >= 0 {
|
||||
num += int(num1[i] - '0')
|
||||
num += int(num1[i] - '0') //转Int
|
||||
i--
|
||||
}
|
||||
if j >= 0 {
|
||||
|
Reference in New Issue
Block a user