目录
一、概述
1、数组
1.1、四种初始化数组的方式
1.2、数组遍历
1.3、数组使用注意事项和细节
1.4、二维数组
1.5、二维数组的遍历
2、切片slice
2.1、切片的使用
2.2、切片的遍历
2.3、string和slice
3、map
3.1、map使用的方式
3.2、map的增删改查操作
3.3、map切片
3.4、map排序
3.5、map使用细节
二、排序和查找
1、排序
2、查找
数组的定义
var 数组名 [数组大小]数据类型
var a[5]int
赋初值 a[0] =1 a[1]=20 .....
访问数组元素
数组名[下标]
package main
import (
"fmt"
)
func main(){
var arr [3]int
arr[0] =10
arr[1] =20
arr[2] =30
fmt.Printf("arr的地址=%p \narr[0]的地址%p \narr[1]的地址%p \narr[2]的地址%p\n",&arr,&arr[0],&arr[1],&arr[2])
}
package main
import (
"fmt"
)
func main(){
var arr1 [3]int =[3]int {1,2,3}
var arr2 =[3]int {1,2,3}
var arr3 =[...]int {6,7,8,9}
var arr4 =[3]string {1:"t",2:"m",0:"r"}
fmt.Println(arr1)
fmt.Println(arr2)
fmt.Println(arr3)
fmt.Println(arr4)
}
方式1:
var arr1 [3]int =[3]int {1,2,3}
for i:=0;i
1.3、数组使用注意事项和细节
- 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
- var arr []int 这时 arr就是一个slice切片。
- 数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。
- 数组创建后,如果没有赋值,有默认值
- 数值类型数组:默认值为0
- 字符串数组: 默认值为""
- bool数组: 默认值为false
- 使用数组的步骤 1.声明数组并开辟空间 2.给数组各个元素赋值 3.使用数组
- 数组的下标是从0开始的
- 数组下标必须在指定范围内使用,否则报panic:数组越界
- Go的数组属值类型,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响。
- 如想在其他函数中,去修改原来的数组,可以使用引用传递(指针方式)
- 长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度。
1.4、二维数组
基本语法:
var 数组名 [大小][大小]类型
方式2:直接初始化
var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值..},{初值..}}
二维数组在声明时也有对应的四种写法(和一维数组类似)
var arr1 [3][3]int =[3][3]int {{1,2,3},{4,5,6},{7,8,9}}
var arr2 [3][3]int =[...][3]int {{1,2,3},{4,5,6},{7,8,9}}
var arr3 =[3][3]int {{1,2,3},{4,5,6},{7,8,9}}
var arr4 =[...][3]int {{1,2,3},{4,5,6},{7,8,9}}
fmt.Println(arr1)
fmt.Println(arr2)
fmt.Println(arr3)
fmt.Println(arr4)
1.5、二维数组的遍历
方式1:双层for循环完成遍历
方式2:for...range方式遍历
var arr [3][3]int =[3][3]int {{1,2,3},{4,5,6},{7,8,9}}
for i := 0;i
2、切片slice
- 切片的英文是slice
- 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。
- 切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样
- 切片的长度是可以变化的,因此切片是一个可以动态变化数组
- 切片定义的基本语法:
- var 变量名 []类型
- 比如:var a []int
- 切片初始化时,仍然不能越界。范围[0-len(arr)]之间,但是可以动态增长。
1.var slice = arr[0:end] 可以简写var slice = arr[:end]
2.var slice = arr[start:len(arr)] 可以简写var slice = arr[start:]
3.var slice = arr[0:len(arr)] 可以简写var slice = arr[:]
- cap是一个内置函数,用于统计切片的容量,即最大可以放多少个元素
- 切片定义完还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用。
- 切片可以继续切片
var arr [5]int = [...]int{11,22,33,44,55}
slice := arr[1:4]
slice2 := slice[1:2]
- 用append内置函数,可以对切片进行动态追加
package main
import (
"fmt"
)
func main(){
var slice []int = []int {1,2,3}
slice = append(slice,10,20,30)//追加具体元素
var a = []int {100,200}
slice = append(slice,a...)//在切片上追加切片
fmt.Println("slice=",slice)
fmt.Println("slice 的len=",len(slice))
fmt.Println("slice 的容量=",cap(slice))
}
-------------------------------------
切片append操作的底层原理分析:
1.切片append操作的本质就是对数组扩容
2.go底层会创建一下新的数组newArr(安装扩容后大小)
3.将slice原来包含的元素拷贝到新的数组newArr
4.slice重新引用到newArr
5.注意newArr是在底层来维护的,程序员不可见
- 切片使用copy内置函数完成拷贝
copy(p1,p2):p1和p2都是切片类型
package main
import (
"fmt"
)
func main(){
var a = []int {100,200}
var slice []int = make([]int,10)
fmt.Println("slice=",slice)
copy(slice,a)
fmt.Println("slice=",slice)
}
-------------------------------------
面试题:
下面代码有没有错误
var a = []int {1,2,3,4,5}
var slice []int = make([]int,2)
fmt.Println("slice=",slice)
copy(slice,a)
fmt.Println("slice=",slice)
//没有错误,可以运行,拷贝满就不拷贝了。
- 切片是引用类型,所以在传递时,遵守引用传递机制。
package main
import (
"fmt"
)
func main(){
var arr [5]int = [...]int{11,22,33,44,55}
slice := arr[1:3]
fmt.Println("arr=",arr)
fmt.Println("slice=",slice)
fmt.Println("slice 的len=",len(slice))//slice 的len= 2
fmt.Println("slice 的容量=",cap(slice))//slice 的容量= 4
fmt.Printf("arr[1]的地址=%p\n",&arr[1])//arr[1]的地址=0xc0000123c8
fmt.Printf("slice[0]的地址=%p\n",&slice[0])//slice[0]的地址=0xc0000123c8
}
slice从底层来说,其实就是一个数据结构(struct结构体)
type slice struct {
ptr *[2]int
len int
cap int
}
2.1、切片的使用
方式1: 定义一个切片,然后让切片去引用一个已经创建好的数组,比如上面的案例
方式2: 通过make来创建切片。
基本语法:
var 切片名 []type = make([],len,[cap])
参数说明:type:就是数据类型 len:大小 cap:指定切片容量,可选
------------------------------------------------------
1.通过make方式创建切片可以指定切片的大小和容量
2.如果没有给切片赋值,那么会使用默认值
3.通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice去访问各个元素
package main
import (
"fmt"
)
func main(){
var slice []int = make([]int,4)
fmt.Println("slice=",slice)//slice= [0 0 0 0]
fmt.Println("slice 的len=",len(slice))//slice 的len= 4
fmt.Println("slice 的容量=",cap(slice))//slice 的容量= 4
}
方式3: 定义一个切片,直接就指定具体数组,使用原理类似make的方式
package main
import (
"fmt"
)
func main(){
var slice []int = []int {1,2,3}
fmt.Println("slice=",slice)
fmt.Println("slice 的len=",len(slice))
fmt.Println("slice 的容量=",cap(slice))
}
面试题:
方式1和方式2的区别
方式1是直接引用数组,这个数组是事前存在的,程序员是可见的。
方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的
2.2、切片的遍历
切片的遍历和数组一样,也有两种方式
1.for循环常见方式遍历
2.for-range结构遍历切片
2.3、string和slice
- string底层是一个byte数组,因此string也可以进行切片处理
- string和切片在内存的形式
- stirng是不可变的,也就是说不能通过str[0]='z'方式来修改字符串
- 如果需要修改字符串,可以先将string-->[]byte /或者[]rune-->修改-->重写转成string
package main
import (
"fmt"
)
func main(){
str := "hello@world!"
slice := str[6:]
fmt.Println("slice=",slice)
arr := []byte(str)//byte不能处理中文--中文处理替换为rune因为rune按字符处理,兼容汉字
arr[0]='z'
str = string(arr)
fmt.Println("str=",str)
}
//斐波那契数列输出实现如下:
提示:斐波那契数组形式:
a[0]=1,a[1]=1,a[2]=a[1]+a[0].....
----------------------------------------
package main
import (
"fmt"
)
func main(){
fSlice := fbn(10)
fmt.Println("fSlice=",fSlice)
}
func fbn(n int) ([]uint64){
fSlice := make([]uint64,n)
fSlice[0] =1
fSlice[1] =1
for i :=2;i
3、map
map是key-value数据结构,又称为字段或者关联数组。
基本语法:
var map变量名 map[keytype]valuetype
key可以是什么类型
Golang中的map的key可以是很多种类型,比如 bool,数字,string,指针,channel,
还可以是只包含前面几个类型的 接口,结构体,数组
通常为int、string
注意:slice,map还有function不可以,因为这几个没法用==来判断
value可以是什么类型
valuetype的类型和key基本一样
通常为:数字(整数,浮点数),string,map,struct
map声明举例:
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string
注意:声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用。
package main
import (
"fmt"
)
func main(){
var a map[string]string
a = make(map[string]string,10)
a["n01"]="s1"
a["n02"]="s2"
a["n03"]="s3"
a["n01"]="s10"
fmt.Println(a)
}
//map在使用前一定要make
//map的key是不能重复,如果重复了,则以最后这个key-value为准
//map的value是可以相同的
//map的key-value是无序
//make内置函数
3.1、map使用的方式
方式1:
//先声明,后make
var a map[string]string
a = make(map[string]string,10)
方式2:
//声明,就直接make
var a =make(map[string]string)
方式3:
//声明,直接赋值
var a map[string]string = map[string]string{
"n01":"s20",
}
a["n02"] = "s30"
3.2、map的增删改查操作
map增加和更新:
map["key"] = value //如果key没有,则增加,如果key存在就是修改
map删除:
func delete(m map[Type]Type1, key Type):内建函数delete按照指定的键将元素从映射中删除。
若m为nil或无此元素,delete不进行操作。
delete(map,"key"):delete是一个内置函数,如果key存在,就删除该key-value,
如果key不存在,不操作,但是也不会报错
var a map[string]string = map[string]string{
"n01":"s20",
}
a["n02"] = "s30"
delete(a,"n01")
1.如果我们要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,逐个删除
2.或者map =make(...),make一个新的,让原来的成为垃圾,被gc回收
map查找:
package main
import (
"fmt"
)
func main(){
var a map[string]string
a = make(map[string]string,10)
a["n01"]="s1"
a["n02"]="s2"
val,ok := a["n01"]
if ok {
fmt.Println("找到了val=",val)
}else{
fmt.Println("没有n01这个key")
}
fmt.Println(a)
}
//说明:如果a这个map中存在"n01",那么ok就会返回true,否则返回false
map遍历:
map的遍历使用for-range的结构遍历
sMap := make(map[string]string)
sMap["n01"]="s1"
sMap["n02"]="s2"
sMap["n03"]="s3"
for k,v := range sMap {
fmt.Printf("k=%v v=%v\n",k,v)
}
map的长度
fmt.Println(len(sMap))
3.3、map切片
切片的数据类型如果是map,则我们称为 slice of map,map切片,这样使用,则map个数就可以动态变化了。
package main
import (
"fmt"
)
func main(){
var sMap []map[string]string
sMap = make([]map[string]string,2)
a := make(map[string]string)
a["name"]="n1"
a["age"]="18"
sMap =append(sMap,a)
fmt.Println(sMap)
}
3.4、map排序
- map默认是无序的
- map排序,是先将key进行排序,然后根据key值遍历输出即可
package main
import (
"fmt"
"sort"
)
func main(){
map1 := make(map[int]int,10)
map1[1] =100
map1[3] =6
map1[19] =33
map1[2] =2
map1[8] =9
fmt.Println(map1)
var keys []int
for k,_ := range map1{
keys = append(keys,k)
}
sort.Ints(keys)
fmt.Println(keys)
for _,k := range keys{
fmt.Printf("map1[%v]=%v\n",k,map1[k])
}
}
3.5、map使用细节
- map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map。
- map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说,能动态增长键值对
- map的value也经常使用struct类型
二、排序和查找
1、排序
排序是将一组数据,依指定的顺序进行排列的过程。
排序的分类:
1、内部排序:
指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法,选择式排序法和插入式排序法)
- 交换式排序法
- 冒泡排序
- 快速排序
2.外部排序法
数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法)。
package main
import (
"fmt"
)
//冒泡排序
func BubbleSort(arr []int){
fmt.Println("排序前arr=",arr)
for i :=0;iarr[j+1]{
tmp := arr[j]
arr[j]=arr[j+1]
arr[j+1]=tmp
}
}
}
fmt.Println("排序后arr=",arr)
}
func main(){
slice := []int {7,4,6,9,1}
BubbleSort(slice)
}
2、查找
在Golang中,常用的查找有2种:顺序查找/二分查找(前提是该数组是有序的)
package main
import (
"fmt"
)
//二分查找 arr从小到大
func BinaryFind(arr []int,leftIndex int,rightIndex int,findVal int){
if leftIndex > rightIndex {
fmt.Println("找不到")
return
}
middle := (leftIndex+rightIndex)/2
if arr[middle] > findVal{
BinaryFind(arr,leftIndex,middle-1,findVal)
}else if arr[middle]==findVal{
fmt.Printf("找到了,下标为%v\n",middle)
}else{
BinaryFind(arr,middle+1,rightIndex,findVal)
}
}
func main(){
arr := []int{1,8,10,89,100,290}
BinaryFind(arr,0,len(arr)-1,10)
}
干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天!
你可能感兴趣的:(golang,学习,java)