Go语言数组、切片、排序、查找、map
Go语言数组、切片、排序、查找、map
数组定义:
var数组名[数组大小]数据类型:var a [5]int
赋初值a[0]=1 a[1]= 30 ....
内存布局【重要】:
①数组的地址可以通过数组名来获取&intArr
②数组的第一个元素的地址,就是数组的首地址
③数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 ->8;int32->4...
④4种初始化数组的方式:
var numArre1 [3] int = [3]int{1, 2,3}
var numArre2 = [3]int{5,6,7}
var numArre3 =[...]int{8,9,10}
var numArre4 =[...]int{1: 800, 0: 900,2:999}
strArre5 :=[...]string{1: "tom", 0: "jack",2 : "many"}
⑤数组的遍历:
常规遍历;
for-range遍历:
for index, value := range array01 {…}
A.第一个返回值index是数组的下标
B.第二个value是在该下标位置的值
C.他们都是仅在for循环内部可见的局部变量
D.遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线_
E.index和value的名称不是固定的,即程序员可以自行指定。
⑥注意事项
A.数组一旦声明,长度固定,无法动态改变。
B.var arr []int:这时arr就是一个slice 切片。数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。
C.数组创建后,如果没有赋值,有默认值。
D.数组下标从0开始。
E.数组下标必须在指定范围内使用,否则报panic:数组越界。
F.Go的数组属值类型,默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响。
G.如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
H.在传递函数参数时,需要考虑数组的长度:不能把[3]int传递给[]int
切片slice:
①切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。
②切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样。
③切片的长度是可以变化的,因此切片是一个可以动态变化数组。
④切片定义的基本语法:var 切片名 类型


slice从底层来说,其实就是一个数据结构(struct结构体)
type slice struct {
ptr *[2]int
len int
cap int
}
切片的使用:
①定义一个切片,让切片去引用一个已经创建好的数组。(程序员可见)

②make创建切片:var切片名 []type = make([]type, len, [cap])
如果分配了cap,则要求cap≥len
默认值int , float → 0;string → "";bool → false
通过make方式创建的切片对应的数组是由make底层维护,(程序员不可见)对外不可见,即只能通过 slice去访问各个元素。
③定义一个切片,直接就指定具体数组。

切片的遍历:for循环、for-range结构

①切片初始化时var slice = arr[stantIndex : endIndex]
从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
②切片初始化时,仍然不能越界。但是可以动态增长。
var slice = arr[0:end]可以简写var slice = arr[:end]
var slice= arr[start:len(arr)]可以简写var slice = arr[start:]
var slice =arr[0:len(arr)]可以简写var slice = arr[:]
③cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
④切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用。
⑤切片可以继续切片。(如上图slice2)
⑥用append内置函数,可以对切片进行动态追加。(如上图slice3)
append原理:
本质是对数组扩容;
go底层会创建一下新的数组newArr(安装扩容后大小);
将slice原来包含的元素拷贝到新的数组newArr;
slice重新引用到newArr;
newArr是在底层来维护的,程序员不可见。
⑦切片的拷贝操作

copy(para1, para2)参数的数据类型是切片
slice4和slice5的数据空间是独立的,slice4[0]=999,slice5[0]=1
⑧切片是引用类型,传递时遵守引用传递机制。
String和slice:
①string底层是一个byte数组,可以进行切片处理。
②string是不可变的,不能通过st[0]=’z’来修改字符串。
如果需要修改字符串,可以先将string→[] byte或[]rune→修改→重写转成string
排序
①内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。(交换式排序法、选择式排序法、插入式排序法)
②外部排序法:数据量过大,借助外部存储进行排序。(合并排序法、直接合并排序法)。
冒泡排序(Bubble Sorting)
基本思想:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素的排序码,若发现逆序则交换,使排序码较小的元素逐渐从后部移向前部。
如果一趟比较下来没有进行交换,就说明序列有序。因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较(优化)。

查找:
顺序查找:

二分查找(该数组是有序的)
思路:要找的数是findval
①arr是一个有序数组,从小到大排序
②先找到中间的下标middle=(leftlndex+rightIndex)/2,让middle对应的值和findval进行比较 如果arr[middle]> findval,令leftIndex = middle - 1
如果arr[middle]< findval,令rightlndex = middle+1
如果arr[middle]= findval,就找到
上面的逻辑会递归执行
如果 leftIndex>rightIndex,则找不到
二维数组

四种声明/定义写法:
var数组名 [大小][大小]类型 = [大小][大小]类型{{初值..},{初值..}}
var数组名 [大小][大小]类型 = [...][大小]类型{{初值..},{初值..}}
var数组名 = [大小][大小]类型{{初值..},{初值..}}
var数组名 = [...][大小]类型{{初值..},{初值..}}
二位数组的遍历:for循环遍历、for-range遍历

map
map是key-value数据结构,又称为字段或者关联数组。
var map变量名map[keytype]valuetype.
golang中的map的key可以是很多种类型,比如 bool,数字,string,指针,channel,还可以是只包含前面几个类型的接口,结构体,数组。通常key为int 、string
Slice、map、function不可以,因为这几个没法用 == 来判断
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,分配内存后才能赋值和使用。
②map的key是不能重复,如果重复了,则以最后这个key-value为准。
③map的value是可以相同的。
④map的key-value是无序的
⑤make内置函数数目
内建函数make分配并初始化一个类型为切片、映射、或通道的对象。
其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。
切片:size指定了其长度。该切片的容量等于其长度。切片支持第二个整数实参可用来指定不同的容量;它必须不小于其长度,因此make([]int,0,10)会分配一个长度为0,容里为10的切片。
映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个小的起始大小。
通道:通道的缓存根据指定的缓存容量初始化。若size为零或被省略,该信道即为无缓存的。
map的使用:

①增加和更新:
map[ "key"]= value。如果key还没有,就是增加,如果 key存在就是修改。
②删除:
delete(map,"key"),delete是一个内置函数,如果key存在,就删除该key-value,如果key不存在,不操作,但是也不会报错。
如果要删除map的所有key ,可以遍历一下key,逐个删除或者map = make(...),make一个新的,让原来的成为垃圾,被g回收。
③查找:

④map的长度:
func len(v Type) int
内建函数len返回v的长度,这取决于具体类型:
数组:v中元素的数量
数组指针:v中元素的数量(v为ni1时panic)
切片、映射:v中元素的数量:若v为nil,len(v)即为零
字符串:v中字节的数量
通道:通道缓存中队列(未读取)元素的数量;若v为nil,len(v)即为零
⑤遍历:使用for-range

map切片:map个数可以动态变化了
案例:使用一个map来记录monster的信息name和age。一个monster对应一个map,并且妖怪的个数可以动态的增加 → map切片

Map排序:
①golang中没有一个专门的方法针对map 的key进行排序。
②golang中的map默认是无序的,不是按照添加的顺序存放的,你每次遍历,得到的输出可能不一样。
③golang中map的排序,是先将key进行排序,然后根据key值遍历输出即可。

Map使用细节:
① map是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的map。
②map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说 map能动态的增长键值对(key-value)
③map的value也经常使用struct类型,更适合管理复杂的数据。
练习:
①使用map[string]map[string]sting的map类型
②key:表示用户名,是唯一的,不可以重复
③如果某个用户名存在,就将其密码修改"888888",如果不存在就增加这个用户信息:(包括昵称nickname和密码pwd) 。
④编写一个函数modifyUser(users map[string]map[string]sting, name string)完成上述功能。
