自己的golang学习及速查笔记——常用数据结构【数组、切片、map、list、string、nil】

本文主要是介绍自己的golang学习及速查笔记——常用数据结构【数组、切片、map、list、string、nil】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 6. 数组
    • 常见的数组定义1(废弃)
    • 常见的数组定义2(废弃)
    • 6.1 数组的声明
    • 6.2 数组的声明及初始化
    • 6.3 数组的比较
    • 6.4 数组的遍历
    • 6.5 数组的截取
  • 7. 多维数组
    • 7.1 多维数组的声明及初始化
    • 7.2 同类型的数组之间可以直接赋值
  • 8. 切片
    • 8.1 从数组或切片生成切片
    • 8.2 声明新的切片
    • 8.3 使用make()构造切片
    • 8.4 append()
      • 8.4.1 在尾部添加元素
      • 8.4.2 在头部添加元素
      • 8.4.3 append性能分析
    • 8.5 copy()
    • 8.6 删除元素
      • 8.6.1 从尾部删除元素
      • 8.6.1 从头部删除元素
      • 8.6.3 从中间删除元素
      • 8.6.4 提示
    • 8.7 利用range遍历切片
  • 9. 多维切片
  • 10. map映射(字典)
    • 10.1 map的容量
    • 10.2 map判断key是否存在
    • 10.3 用切片作为 map 的值
    • 10.4 map的遍历
    • 10.5 map的删除、清空
    • 10.6 并发环境下的mapSync
  • 11. list列表
    • 11.1 初始化list
    • 11.2 在list中插入元素
    • 11.3 从列表中删除元素
    • 11.4 列表的遍历
  • 12. string
    • 12.1 与其他语言的主要差异
    • 12.2 Unicode 与 UTF-8的区别
    • 12.3 string的遍历
    • 12.4 常用函数【split, join,atoi,itoa】
  • 13. nil:空值和零值

6. 数组

这里要注意golang里的数组是使用值传递,而不是像js那样采用引用传递的

var a = [3]int{1,2,3}
var b = [3]int{}
b = a
b[0] = 4
a[0]仍等于1

常见的数组定义1(废弃)

 1 package main2 import "fmt"3 func main() {4     这里我们创建了一个数组 a 来存放刚好 5int。元素的类型和长度都是数组类型的一部分。数组默认是零值的,对于int数组来说也就是 06     var a [5]int8     我们可以使用 array[index] = value 语法来设置数组指定位置的值,或者用 array[index] 得到值。
10     a[4] = 10013     使用内置函数 len 返回数组的长度
15     fmt.Println("len:", len(a))16     使用这个语法在一行内初始化一个数组
18     b := [5]int{1, 2, 3, 4, 5}
19     fmt.Println("dcl:", b)20     数组的存储类型是单一的,但是你可以组合这些数据来构造多维的数据结构。
22     var twoD [2][3]int
23     for i := 0; i < 2; i++ {
24         for j := 0; j < 3; j++ {
25             twoD[i][j] = i + j
26         }
27     }
28     fmt.Println("2d: ", twoD)
29 }

常见的数组定义2(废弃)

func main () {// 数组声明及赋值var arr [4]intarr[0] = 2arr[1] = 7arr[2] = 11arr[3] = 15// 声明的同时赋值// ...表示让编译器确定数组大小var arr2 = [...]int {2,7,11,15}// orarr3 := [4]int {} // 默认以0填充
}

6.1 数组的声明

var a [3]int

6.2 数组的声明及初始化

数组若初始化但不生命,默认为0

var q [3]int = [3]int {1,2,3}var q = [3]int {1,2,3}
或
q := [3]int {}

若不确定数量,以…代替数量,系统会自动推断数组大小

q := [...]int {1,2,4,6,7,8}

6.3 数组的比较

如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,这时候我们可以直接通过 == 比较运算符来比较两个数组,只有当两个数组的所有元素都是相等的时候数组才是相等的。

a := [2]int{1, 2}
b := [...]int{1, 2}
c := [2]int{1, 3}
fmt.Println(a == b, a == c, b == c) // "true false false"
d := [3]int{1, 2}
fmt.Println(a == d) // 编译错误:无法比较 [2]int == [3]int

6.4 数组的遍历

var team [3]string
for k, v := range team {fmt.Println(k, v)
}

6.5 数组的截取

nums[开始索引(包含), 结束索引(不包含)]
a := [...]int{1,2,3,4,5}
a[1:3] // 2,3
a[1:len(a)] // 2,3,4,5
a[1:] // 2,3,4,5
a[:3] // 1,2,3
go语言是不支持负数索引的

7. 多维数组

7.1 多维数组的声明及初始化

// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化外层数组中索引为 1 个和 3 的元素
array := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化外层数组和内层数组的单个元素
array := [4][2]int{1: {0: 20}, 3: {1: 41}}

下图展示了上面示例中声明的二维数组在每次声明并初始化后包含的值。
在这里插入图片描述

7.2 同类型的数组之间可以直接赋值

var array1 [2][2]int
var array2 [2][2]int
array2 = array1
// 将 array1 的索引为 1 的维度复制到一个同类型的新数组里
var array3 [2]int = array1[1]
// 将外层数组的索引为 1、内层数组的索引为0 的整型值复制到新的整型变量里
var value int = array1[1][0]

8. 切片

https://www.cnblogs.com/liuzhongchao/p/9159896.html 这个博客讲的好
切片(slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。

切片其实是一个结构体:

  • ptr
  • len
  • cap

注意到它是有len和cap两个属性的,也就是说如果当前的len>cap时,它就要寻找一片新的扩容后的连续存储空间,这也意味着它要经常的复制,来移动内存。

8.1 从数组或切片生成切片

切片默认指向一段连续内存区域,可以是数组,也可以是切片本身。

slice[开始位置:结束位置] (不包括结束位置)
var a = [3]int {1,2,3}
fmt.Println(a, a[1:2])
// [1, 2, 3] [2]

从数组或切片生成新的切片拥有如下特性:

  • 取出的元素数量为:结束位置-开始位置。
  • 取出元素不包含结束位置对应的索引,切片最后一个元素使用 slice[len(slice)] 获取。
  • 当缺省开始位置时,表示从连续区域开头到结束位置。
  • 当缺省结束位置时,表示从开始位置到整个连续区域末尾。
  • 两者同时缺省时,与切片本身等效。
  • 两者同时为0时,等效于空切片,一般用于切片复位。

由于切片是引用类型,若想清空切片所指

a := []int {1,2,3}
fmt.Println(a[0:0])

8.2 声明新的切片

除了从原有的数组或者切片中生成切片,你也可以声明一个新的切片。
每一种类型都可以拥有其切片类型,表示多个类型元素的连续集合。因此切片类型也可以被声明。切片类型声明格式如下:

var name []type

举例:

// 声明字符串切片
var strList []string
// 声明整型切片
var numList []int
// 声明一个空切片
var numListEmpty = []int{}
// 输出3个切片
fmt.Println(strList, numList, numListEmpty)
// 输出3个切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))
// 切片判定空的结果
fmt.Println(strList == nil)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil)

代码输出结果:

[] [] []
0 0 0
true
true
false

代码说明如下:

  • 第 2 行,声明一个字符串切片,切片中拥有多个字符串。
  • 第 5 行,声明一个整型切片,切片中拥有多个整型数值。
  • 第 8 行,将 numListEmpty 声明为一个整型切片。本来会在{}中填充切片的初始化元素,这里没有填充,所以切片是空的。但此时 numListEmpty 已经被分配了内存,但没有元素。
  • 第 11 行,切片均没有任何元素,3 个切片输出元素内容均为空。
  • 第 14 行,没有对切片进行任何操作,strList 和 numList 没有指向任何数组或者其他切片。
  • 第 17 行和第 18 行,声明但未使用的切片的默认值是 nil。strList 和 numList 也是 nil,所以和 nil 比较的结果是 true。
  • 第 19 行,numListEmpty 已经被分配到了内存,但没有元素,因此和 nil 比较时是 false。

切片是动态结构,只能与nil判定相等,不能互相判等时。

声明新的切片后,可以使用 append() 函数来添加元素。

8.3 使用make()构造切片

如果需要动态地创建一个切片,可以使用 make() 内建函数,格式如下:

make([]type, len, cap)
  • type:切片的元素类型。
  • size:就是为这个类型分配多少个元素。
  • cap:预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题。

示例:

a := make([]int, 2)
b := make([]int, 2, 10)fmt.Println(a, b)
// [0 0] [0 0]
fmt.Println(len(a), len(b))
// 2 2
a 和 b 均是预分配 2 个元素的切片,只是 b 的内部存储空间已经分配了 10 个,但实际使用了 2 个元素。
容量不会影响当前的元素个数,因此 a 和 b 取 len 都是 2

温馨提示
使用 make() 函数生成的切片一定发生了内存分配操作。但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。
在这里插入图片描述

切片不一定必须经过 make() 函数才能使用。生成切片、声明后使用 append() 函数均可以正常使用切片。

8.4 append()

要注意,append返回一个新的东西,必须要再赋值

8.4.1 在尾部添加元素

var a []int
// 追加一个元素
a = append(a, 1)
// 追加多个元素
a = append(a, 1, 2, 3)
// 追加一个切片,需要手动解包,类比es6的...运算符
a = append(a, []int{1,2,3}...)

8.4.2 在头部添加元素

var a = []int{1,2,3}
// 在开头添加1个元素
a = append([]int{0}, a...)
// 在开头添加1个切片
a = append([]int{-3,-2,-1}, a...)

8.4.3 append性能分析

我们要注意切片的len和cap是两个概念,从名字上来看,len是长度,cap是容量,乍一看有一些难理解,但是只要稍微对比较偏底层的语言理解一些就很好理解。

  • 长度:就是当前切片已有的元素数量
  • 容量:当前切片在不扩容、不重新分配内存的情况下能容纳的元素数量

为什么要强调cap?因为切片在扩容的时候是按照1、2、4、8、16…这样来扩容的,每一次扩容必定会重新分配内存,相当于重新创建了一个切片,指向的地址也会改变,比较消耗时间和资源。

8.5 copy()

把sllice2的内容拷贝的slice1,返回值是成功的个数

return copy(slice1, slice2)

Go语言的内置函数 copy() 可以将一个切片的内容复制到另一个切片。
如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制。

与append不同的是,append要在操作结束后再赋值给原目标切片,而copy不用

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

8.6 删除元素

Go语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素。根据要删除元素的位置有三种情况:从开头位置删除,从中间位置删除,从尾部删除。其中删除切片尾部的元素最快。

8.6.1 从尾部删除元素

从尾部删除n个元素:

var a = []int{1,2,3,4,5}
a = a[:len(a)-N]

8.6.1 从头部删除元素

从开头删除n个元素

  • 移动头部指针:
    var a = []int{1,2,3,4,5}
    a = a[n:]
    
  • 原地完成
    var a = []int{1, 2, 3}
    a = append(a[:0], a[n:]...) // 删除开头n个元素
    
  • 利用copy
    var a = []int{1, 2, 3}
    a = a[:copy(a, a[N:])] // 删除开头n个元素
    

8.6.3 从中间删除元素

var a = []int{1, 2, 3, ...}
a = append(a[:i], a[i+1:]...) // 删除中间1个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素

8.6.4 提示

Go 语言中切片元素的删除过程并没有提供任何的语法糖或者方法封装,无论是初学者学习,还是实际使用都是极为麻烦的。

连续容器的元素删除无论是在任何语言中,都要将删除点前后的元素移动到新的位置。随着元素的增加,这个过程将会变得极为耗时。因此,当业务需要大量、频繁地从一个切片中删除元素时,如果对性能要求较高,就需要反思是否需要更换其他的容器(如双链表等能快速从删除点删除元素)。

8.7 利用range遍历切片

当迭代切片时,关键字 range 会返回两个值。第一个值是当前迭代到的索引位置,第二个值是该位置对应元素值的一份副本。

如果不需要索引值,可以使用占位字符来忽略这个值。

需要强调的是,range 创建了每个元素的副本,而不是直接返回对该元素的引用。

关键字 range 总是会从切片头部开始迭代。如果想对迭代做更多的控制,依旧可以使用传统的 for 循环,代码如下所示。

// 创建一个整型切片
// 其长度和容量都是 4 个元素
slice := []int{10, 20, 30, 40}
// 从第三个元素开始迭代每个元素
for index := 2; index < len(slice); index++ {fmt.Printf("Index: %d Value: %d\n", index, slice[index])
}

在前面几节的学习中我们了解了两个特殊的内置函数 len 和 cap,可以用于处理数组、切片和通道。对于切片,函数 len 返回切片的长度,函数 cap 返回切片的容量。在上面的示例中,使用到了函数 len 来决定什么时候停止对切片的迭代。

9. 多维切片

我觉得这里可以类比为c++中的嵌套vector,每一层又是一个单独的切片,可以有独立的长度。

// 创建一个整型切片的切片
slice := [][]int{{10}, {100, 200}}
[[10],[100, 200]
]

在这里插入图片描述

slice[0] = append(slice[0], 20)

就变成了

[[10, 20],[100, 200]
]

10. map映射(字典)

Go语言中 map 是一种特殊的数据结构:一种元素对(pair)的无序集合,pair 的一个元素是 key,对应的另一个元素是 value,所以这个结构也称为关联数组或字典。这是一种快速寻找值的理想结构:给定 key,对应的 value 可以迅速定位。

map 这种数据结构在其他编程语言中也称为字典(Python)、hash 和 HashTable 等。

注意
map是引用类型的

map的声明、赋值

var varname map[keytype]valuetypevar varname map[string]intm := map[string]int {"one": 1, "two": 2}m := map[string]int {}m := make(map[string]int, cap)

在声明的时候不需要知道 map 的长度,map 是可以动态增长的。未初始化的 map 的值是 nil。

key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float。所以数组、切片和结构体不能作为 key,但是指针和接口类型可以。如果要用结构体作为 key 可以提供 Key() 和 Hash() 方法,这样可以通过结构体的域计算出唯一的数字或者字符串的 key。

value 可以是任意类型的;通过使用空接口类型,我们可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言。

map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果很在乎性能的话还是建议用切片来解决问题。

map 也可以用函数作为自己的值,这样就可以用来做分支结构:key 用来选择要执行的函数。

map 是引用类型的: 内存用 make 方法来分配。

10.1 map的容量

和数组不同,map 可以根据新增的 key-value 对动态的伸缩,因此它不存在固定长度或者最大限制。但是也可以选择标明 map 的初始容量 capacity,格式如下:

make(map[keytype]valuetype, cap)
mymap := make(map[string]float, 100)

当 map 增长到容量上限的时候,如果再增加新的 key-value 对,map 的大小会自动加 1。所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。

10.2 map判断key是否存在

与其他语言不同的是,在访问不存在的key时,返回的是对应数据类型的零值,而不是NULL,因此不能通过nil来判断是否存在。

if value, isExit := m[0]; isExit {if isExit {// pass}
}

10.3 用切片作为 map 的值

既然一个 key 只能对应一个 value,而 value 又是一个原始类型,那么如果一个 key 要对应多个值怎么办?例如,当我们要处理 unix 机器上的所有进程,以父进程(pid 为整形)作为 key,所有的子进程(以所有子进程的 pid 组成的切片)作为 value。通过将 value 定义为 []int 类型或者其他类型的切片,就可以优雅的解决这个问题。

这里有一些定义这种 map 的例子:

mp1 := make(map[int][]int)
mp2 := make(map[int]*[]int)

10.4 map的遍历

scene := make(map[string]int)
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
for key, value := range scene {fmt.Println(k, v)
}

只遍历key的时候可以用缺省值代替value也可以省略value

for key := range scene {pass
}

10.5 map的删除、清空

使用 delete() 内建函数从 map 中删除一组键值对,delete() 函数的格式如下:

delete(mapname, key)
  • mapname 为要删除的 map 实例。
  • key为要删除的 map 键值对中的键。
    清空 map 中的所有元素

有意思的是,Go 语言中并没有为 map 提供任何清空所有元素的函数、方法。清空 map 的唯一办法就是重新 make 一个新的 map。不用担心垃圾回收的效率,Go 语言中的并行垃圾回收效率比写一个清空函数高效多了。

10.6 并发环境下的mapSync

Go 语言中的 map 在并发情况下,是只读安全的,但是读写是不安全的。

需要并发读写时,一般的做法是加锁,但这样性能并不高。Go 语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map。sync.Map 和 map 不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构。

sync.Map有以下特性:

  • 无须初始化,直接声明即可。
  • sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用。Store 表示存储,Load 表示获取,Delete 表示删除。
  • 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值。Range 参数中的回调函数的返回值功能是:需要继续迭代遍历时,返回 true;终止迭代遍历时,返回 false。
package main
import ("fmt""sync"
)func main() {var scene sync.Map// 将键值对保存到sync.Mapscene.Store("greece", 97)scene.Store("london", 100)scene.Store("egypt", 200)// 从sync.Map中根据键取值fmt.Println(scene.Load("london"))// 根据键删除对应的键值对scene.Delete("london")// 遍历所有sync.Map中的键值对scene.Range(func(k, v interface{}) bool {fmt.Println("iterate:", k, v)return true})
}

sync.Map 没有提供获取 map 数量的方法,替代方法是获取时遍历自行计算数量。sync.Map 为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。

11. list列表

列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。

11.1 初始化list

list 的初始化有两种方法:New 和声明。两种方法的初始化效果都是一致的。

  1. 通过 container/list 包的 New 方法初始化 list
    变量名 := list.New()
    
  2. 通过声明初始化list
    var 变量名 list.List
    

11.2 在list中插入元素

双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront 和 PushBack。

l := list.New()
l.PushBack("fist")
l.PushFront(67)

提示
这两个方法都会返回一个 *list.Element 结构。如果在以后的使用中需要删除插入的元素,则只能通过 *list.Element 配合 Remove() 方法进行删除,这种方法可以让删除更加效率化,也是双链表特性之一。

方法功能
InsertAfter(v interface {}, mark * Element) * Element在 mark 点之后插入元素,mark 点由其他插入函数提供
InsertBefore(v interface {}, mark * Element) *Element在 mark 点之前插入元素,mark 点由其他插入函数提供
PushBackList(other *List)添加 other 列表元素到尾部
PushFrontList(other *List)添加 other 列表元素到头部

11.3 从列表中删除元素

列表的插入函数的返回值会提供一个 *list.Element 结构,这个结构记录着列表元素的值及和其他节点之间的关系等信息。从列表中删除元素时,需要用到这个结构进行快速删除。

package main
import "container/list"
func main() {l := list.New()// 尾部添加l.PushBack("canon")// 头部添加l.PushFront(67)// 尾部添加后保存元素句柄element := l.PushBack("fist")// 在fist之后添加highl.InsertAfter("high", element)// 在fist之前添加noonl.InsertBefore("noon", element)// 使用l.Remove(element)
}

11.4 列表的遍历

l := list.New()
for i := l.Front(); i != nil; i = i.Next() {fmt.Println(i.Value)
}

12. string

12.1 与其他语言的主要差异

  1. string是数据类型。不是引用或指针类型
  2. string是只读的byte slicelen()函数访问的是它包含的byte数,例如
    s := "abc"
    s[0] = '1' // errorlen("严") // 输出3
    
  3. stringbyte数组可以存放任何数据

12.2 Unicode 与 UTF-8的区别

  1. Unicode是一种字符集
  2. UTF-8是Unicode的存储实现

go语言的内置机制,rune可以取出string中的unicode

var s string = "中"
fmt.Println(len(s)) // 3
c := []rune(s)
fmt.Println(len(c)) // 1fmt.Printf("unicode %x\n", s) // unicode e4b8ad
fmt.Printf("utf %x", c[0]) // utf 4e2d

在这里插入图片描述

12.3 string的遍历

  1. strings
  2. strconv

之前提到过,string的长度并不是传统理解的长度,而是byte数组的长度,英文下是正常的,如果要遍历中文字符串要怎么办呢?

go语言这里的通用迭代器range会把string转换为[]rune类型方便我们使用

s := "怪物猎人"for _, v := range s {fmt.Println(v)fmt.Printf("%[1]c %[1]x\n\n", v)
}
24618
怪 602a29289
物 726929454
猎 730e20154
人 4eba

12.4 常用函数【split, join,atoi,itoa】

package mainimport ("fmt""strconv""strings"
)func main() {var s string = "A,B,C,D"var parts []string = strings.Split(s, ",")for _, part := range parts {fmt.Println(part)}var conn string = strings.Join(parts, "-")fmt.Println(conn)if num, err := strconv.Atoi("314159"); err == nil {fmt.Println(num)}var str string = strconv.Itoa(5201314)fmt.Println(str)
}ABCDA-B-C-D3141595201314

13. nil:空值和零值

按照 Go语言规范,任何类型在未初始化时都对应一个零值:布尔类型是 false,整型是 0,字符串是 “”,而指针,函数,interface,slice,channel 和 map 的零值都是 nil。

这篇关于自己的golang学习及速查笔记——常用数据结构【数组、切片、map、list、string、nil】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/758481

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]