• go语言系列-从数组到map


    数组

    数组可以存放多个同一类型数据。数组也是一种数据类型,在Go中,数组是值类型

    一个养鸡场有6只鸡,它们的体重分别是3kg,5kg,1kg,3.4kg,2kg,50kg。请问这六只鸡的总体重是多少?平均体重是多少?

    使用传统的方法不利于数据的管理和维护
    传统的方法不够灵活,因此我们引出需要学习的新的数据类型  ==》数组
    
    //使用数组的方式来解决问题
    var 数组名 [数组大小]数据类型
    var a [5]int
    赋初值 a[0] = 1 a[1] = 30 ...
    func main()  {
       //1.定义一个数组
       var hens [7]float64
       //2. 给数组的每个元素赋值,元素的下标是从0开始的 0 - 6
       hens[0] = 3.0  //hens数组的第1个元素 hens[0]
       hens[1] = 5.0  //hens数组的第2个元素 hens[1]
       hens[2] = 1.0
       hens[3] = 3.4
       hens[4] = 2.0
       hens[5] = 50.0
       hens[6] = 150.0 //增加一只鸡
       //3. 遍历数组求出总体重
       totalWeight := 0.0
       for i := 0; i < len(hens); i++ {
          totalWeight += hens[i]
       }
       //4. 求出平均体重
       avgWeight := fmt.Sprintf("%.2f",totalWeight / float64(len(hens)))
       fmt.Printf("totalWeight = %v avgWeight = %v",totalWeight,avgWeight)
    }
    //输出:totalWeight = 214.4 avgWeight = 30.63
    使用数组来解决问题,增加程序的可维护性
    而且方法代码更加清晰,也容易扩展
    

    数组在内存布局

    数组的地址可以通过数组名来获取 &intArr
    数组的第一个元素的地址,就是数组的首地址
    数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 -> 8    int32 -> 4 ...
    func main()  {
       var intArr [3]int  //int占8个字节
       //当我们定义完数组后,其是数组的各个元素有默认值 0
       fmt.Println(intArr) // 默认值
       intArr[0] = 10
       intArr[1] = 20
       intArr[2] = 30
       fmt.Println(intArr)
       fmt.Printf("intArr的地址 = %p intArr[0] 地址 = %p intArr[1] 地址 = %p intArr[2] 地址 = %p",
          &intArr,&intArr[0],&intArr[1],&intArr[2])
    }
    //输出:[0 0 0]
    //[10 20 30]
    //intArr的地址 = 0xc000010380 intArr[0] 地址 = 0xc000010380 intArr[1] 地址 = 0xc000010388 intArr[2] 地址 = 0xc000010390
    

    数组的使用

    func main()  {
       var score [5]float64
       for i := 0; i < len(score); i++ {
          fmt.Printf("请输入第%d个元素的值
    ",i+1)
          fmt.Scanln(&score[i])
       }
       //变量数组打印
       for i := 0; i < len(score); i++ {
          fmt.Printf("score[%d] = %v	",i,score[i])
         //访问数组元素:数组名[下标]比如:要使用a数组的第三个元素 a[2]
       }
    }
    

    初始化数组的方式

    func main() {
       //四种初始化数组的方式
       var numArr01 [3]int = [3]int{1,2,3}
       fmt.Println("numArr01 = ",numArr01)
    
       var numArr02  = [3]int{4,5,6}
       fmt.Println("numArr02 = ",numArr02)
    
       //这里的 [...]是规定的写法
       var numArr03 = [...]int{7,8,9}
       fmt.Println("numArr03 = ",numArr03)
    
       var numArr04 = [...]int{1: 800, 0: 900, 2: 999}
       fmt.Println("numArr04 = ",numArr04)
    
       //类型推导
       strArr05 := [...]string{1: "zisefeizhu", 0: "jack", 2: "mary"}
       fmt.Println("strArr05 = ",strArr05)
    }
    //输出:numArr01 =  [1 2 3]
    //numArr02 =  [4 5 6]
    //numArr03 =  [7 8 9]
    //numArr04 =  [900 800 999]
    //strArr05 =  [jack zisefeizhu mary]
    

    数组的遍历

    方法1:  常规遍历
    遍历数组求出总体重
       totalWeight := 0.0
       for i := 0; i < len(hens); i++ {
          totalWeight += hens[i]
       }
    
    方法2:for - range 结构遍历
    第一个返回值index是数组的下标
    第二个value是在该下标位置的值
    它们都是仅在for循环内部可见的局部变量
    遍历数组元素的时候,如果不想使用下标index,可以直接把下边index标为下划线_
    index和value的名称不是固定的,即程序员可以自行指定,一般命名为index和value
     //演示for-range遍历数组
       heroes := [...]string{"宋江","吴用","林冲"}
       for i, v := range heroes {
          fmt.Printf("i = %v v = %v
    ",i, v)
          fmt.Printf("heroes[%d] = %v 
    ",i,heroes[i])
       }
       for _,v := range heroes {
          fmt.Printf("元素的值 = %v
    ",v)
       }
    }
    //输出:i = 0 v = 宋江
    //heroes[0] = 宋江 
    //i = 1 v = 吴用
    //heroes[1] = 吴用 
    //i = 2 v = 林冲
    //heroes[2] = 林冲 
    //元素的值 = 宋江
    //元素的值 = 吴用
    //元素的值 = 林冲
    

    数组使用的注意事项和细节

    数组是多个相同类型数组的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化
    var arr []int 这时 arr就是一个slice切片,切片后面专门讲解
    数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混合
    数组创建后,如果没有赋值,有默认值(零值)
    	数值类型数组:默认值为0
    	字符串数组:  默认值为" "
    	bool数组:   默认值为false
    使用数组的步骤 
    	1.声明数组并开辟空间
    	2.给数组各个元素赋值(默认零值)
    	3.使用数组
    数组的下标是从0开始的
    数组下标必须在指定范围内使用,否则报panic:数组越界,比如
    	var arr[5]int 则有效下标为 0 - 4
    Go的数组属于值类型,在默认情况下是值类型,因此会进行值拷贝。数组间不会相互影响
    

    如果想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
    

    长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度
    

    数组的应用案例

    创建一个byte类型的26个元素的数组,分别放置’A’ - ’Z’。使用for循环访问所有元素并打印出来。提示:字符数据运算’A’+1 ->’B’

    func main(){
       //1)创建一个byte类型的26个元素的数组,分别放置’A’ - ’Z’。
       // 使用for循环访问所有元素并打印出来。
       // 提示:字符数据运算’A’+1 ->’B’
    
       //思路
       //1. 声明一个数组 var myChars [26]byte
       //2. 使用for循环,利用 字符可以进行运算的特点来辅助 'A' + 1 = 'B'
       //3. 使用for 循环打印
       var myChars [26]byte
       for i := 0; i < 26; i++ {
          myChars[i] = 'A' + byte(i) //注意需要将i =》 byte
       }
       for i := 0; i < 26; i++ {
          fmt.Printf("%c",myChars[i])
       }
    //输出:ABCDEFGHIJKLMNOPQRSTUVWXYZ
    }
    

    请求出一个数组的最大值,并得到对应的下标

    func main() {
       //思路
       //1. 声明一个数组 var intArr[5] = [...]int{1,-1,9,90,11}
       //2. 假定第一个元素就是最大值,下标就是0
       //3. 然后从第二个元素开始循环比较,如果发现有更大值,则交换
       var intArr [6]int = [...]int {1,-1,9,90,11,9000}
       maxVal := intArr[0]
       maxValIndex := 0
       for i := 1; i < len(intArr); i++ {
          //从第二个元素开始循环比较,如果发现有更大,则交换
          if maxVal < intArr[i] {
             maxVal = intArr[i]
             maxValIndex = i
          }
       }
       fmt.Printf("maxVal = %v maxValIndex = %v", maxVal, maxValIndex)
    }
    //输出:maxVal = 9000 maxValIndex = 5
    

    请求出一个数组的和和平均值。for-range

    func main() {
       //思路
       //1. 声明一个数组 var intArr[5] = [...]int{1,-1,9,90,11}
       //2. 求出和sum
       //3. 求出平均值
       var intArr [5]int = [...]int{1, -1, 9, 90, 12}
       sum := 0
       for _,val := range intArr {
          //累计求和
          sum += val
       }
       //如何让平均值保留到小数
       fmt.Printf("sum = %v 平均值 = %v", sum, float64(sum) / float64(len(intArr)) )
    }
    //输出:sum = 111 平均值 = 22.2
    

    要求:随机生成五个数,并将其反转打印,复杂应用

    import (
       "fmt"
       "math/rand"
       "time"
    )
    
    func main() {
       //思路
       //1. 随机生成5个数,rand.Intn()函数
       //2. 当我们得到随机数后,就放到一个数组int数组
       //3. 反转打印,交换的次数是len/2,倒数第一个和第一个元素交换,倒数第二个和第二个元素交换
       var intArr [5]int
       //为了每次生成的随机数都不一样,我们需要给一个seed值
       len := len(intArr)
       rand.Seed(time.Now().UnixNano())
       for i := 0; i < len; i++ {
          intArr[i] = rand.Intn(100)  //0 <= n < 100
       }
       fmt.Println("交换前",intArr)
       //反转打印,交换的次数是 len / 2
       //倒数第一个和第一个元素交换,倒数第二个和第二个元素交换
       temp := 0 //做一个临时变量
       for i := 0; i < len / 2; i++ {
          temp = intArr[len - 1 - i]
          intArr[len - 1 -i] = intArr[i]
          intArr[i] = temp
       }
       fmt.Println("交换后",intArr)
    }
    //输出:交换前 [24 15 90 17 6]
    //交换后 [6 17 90 15 24]
    

    数组练习题

    题目要求:

    跳水比赛 8个评委打分,运动员的成绩去掉一个最高分,去掉一个最低分,剩下的6个分数的平均分就是最后得分,使现

    (1)请把最高分,最低分的评委找出

    (2)找出最佳评委和最差评委。最佳评委是最后得分差距最小,最差评委最后得分差距最大

    分析:

    设计一个函数求最高分 最低分 平均分 需要考虑存在多个最低分和最高分的情况

    找最有裁判和最差裁判使用abs() 以及切片完成 将绝对值传入到切片中再遍历

    package main
    
    import (
       "fmt"
       "math")
    func max(array  *[8]float64) (mx float64,mi float64,avg float64){
       max := 0.0
       for i := 0; i < len(array); i++ {
          if (*array)[i] > max {
             max = (*array)[i]
          }
       }
       min := max
       for i := 0; i < len(array); i++ {
          if (*array)[i] < min  {
             min = (*array)[i]
          }
       }
       mx = max
       mi = min
       sum := 0.0
       maxcount,mincount :=0.0,0.0
       for i := 0; i < len(array); i++ {
           //判断最大值和最小值出现的次数 1次时直接去掉  多次是需要加上去
          if (*array)[i] == max {
             maxcount +=1
          }
          if (*array)[i] == min{
             mincount +=1
          }
          //算出不包含任意一次不包含 最大值、最小值的和
          if (*array)[i] != max && (*array)[i] != min{
             sum += (*array)[i]
          }
    
       }
       //fmt.Println(maxcount,mincount)
       //处理出现多次最大值或者最小值
       if  mincount > 1.0 && maxcount > 1.0{
          sum += (max*(maxcount-1)+min*(mincount-1))
       }else if mincount > 1.0 && maxcount == 1.0{
          sum += (min*(mincount-1))
       }else if mincount ==1.0  && maxcount > 1.0{
          sum += (max*(maxcount-1))
       }else {
           sum += 0
       }
       avg = sum/6.0
       return  mx,min,avg}
    
    func Best(array1  *[8]float64, arry2 []float64, avg float64) {
    
       for i := 0; i < len(array1); i++ {
          arry2 = append(arry2, math.Abs((*array1)[i]-avg))
       }
       max  := 0.0
       for j :=0;j < len(arry2);j++{
          if arry2[j] > max{
             max = arry2[j]
          }
       }
       min := max
       for i := 0; i < len(arry2); i++ {
          if arry2[i] < min  {
             min = arry2[i]
          }
       }
       for i := 0; i < len(arry2); i++ {
          if arry2[i] == min {
             fmt.Printf("最优秀评分者为第%v位裁判,评分:%v 和平均分相差%v
    ",i+1,(*array1)[i],min)
          }
       }
    
       for i := 0; i < len(arry2); i++ {
          if arry2[i] == max  {
             fmt.Printf("评分差距最大者为第%v位裁判,评分:%v和平均分相差%v
    ",i+1,(*array1)[i],max)
          }
       }}
    
    var Socre [8]float64
    var Socreabs = make([]float64,0,0)
    func main() {
       //输入8个裁判的分数
       for  i := 0;i<len(Socre);i++{
          fmt.Printf("请输入第%v位裁判的的评分:
    ",i+1)
          fmt.Scanln(&Socre[i])
       }
    
       max,min,avg :=max(&Socre)
       fmt.Println(Socre)
       fmt.Printf("最高分为:%v,最低分为:%v 平均分为:%v
    ",max,min,avg)
       //知道最大分  最小分 找最大分、最小分的裁判
       for k :=0;k<len(Socre);k++{
          if Socre[k] == max{
             fmt.Printf("最高分为:%v,第%v位裁判
    ",max,k+1)
          }else if Socre[k] == min {
             fmt.Printf("最低分:%v,第%v位裁判
    ",min,k+1)
          }
       }
       Best(&Socre,Socreabs,avg)
    
    }
    

    切片

    切片的英文是slice
    切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制
    切片的使用和数组类似,遍历切片、访问切片的元素和求切片长度len(slice)都一样
    切片的长度是可以变化的,因此切片是一个可以动态变化的数组

    var 切片名 []类型
    比如: var  a  []int
    
    func main()  {
       //演示切片的基本使用
       var intArr [5]int = [...]int {1,22,33,66,99}
       //声明/定义一个切片
       //1. slice := intArr[1:3]
       //2. intArr[1:3]表示slice引用到intArr这个数组
       //3. 引用intArr数组的起始下标为1,最后的下标为3(但是不包含3)
       slice := intArr[1:3]
       fmt.Println("intArr = ",intArr)
       fmt.Println("slice 的元素是 = ",slice) // 22,33
       fmt.Println("slice 的元素个数 = ",len(slice)) // 2
       fmt.Println("slice 的容量 = ", cap(slice)) //切片的容量是可以动态变化
    }
    //输出:intArr =  [1 22 33 66 99]
    //slice 的元素是 =  [22 33]
    //slice 的元素个数 =  2
    //slice 的容量 =  4
    

    切片在内存中形式【重要】

    对上面的分析图总结

    slice的确是一个引用类型
    slice从底层来说,其实就是一个数据结构(struct结构体)
    	type slice struct {
    		ptr *[2]int
    		len int
    		cap int
    	}
    

    切片的使用

    方式1:定义一个数组,然后让切片去引用一个已经创建好的数组
    func main()  {
       //演示切片的基本使用
       var intArr [5]int = [...]int {1,22,33,66,99}
       //声明/定义一个切片
       //1. slice := intArr[1:3]
       //2. intArr[1:3]表示slice引用到intArr这个数组
       //3. 引用intArr数组的起始下标为1,最后的下标为3(但是不包含3)
       slice := intArr[1:3]
       fmt.Println("intArr = ",intArr)
       fmt.Println("slice 的元素是 = ",slice) // 22,33
       fmt.Println("slice 的元素个数 = ",len(slice)) // 2
       fmt.Println("slice 的容量 = ", cap(slice)) //切片的容量是可以动态变化
    }
    //输出:intArr =  [1 22 33 66 99]
    //slice 的元素是 =  [22 33]
    //slice 的元素个数 =  2
    //slice 的容量 =  4
    
    方式2:通过make来创建切片
    var 切片名 []type = make([]type,len,[cap])
    参数说明:
    	type:就是数据类型
    	len :大小
    	cap :指定切片容量,可选,如果分配了cap,则要求cap >= len 
    func main() {
       //演示切片的使用 make
       var slice []float64 = make([]float64, 5, 10)
       slice[1] = 10
       slice[3] = 20
       //对于切片,必须make使用
       fmt.Println(slice)
       fmt.Println("slice的size = ",len(slice))
       fmt.Println("slice的cap  = ",cap(slice))
    }
    //输出:[0 10 0 20 0]
    //slice的size =  5
    //slice的cap  =  10
    

    对上面代码的小结:
    1)通过make方式创建切片可以指定切片的大小和容量
    2)如果没有给切片的各个元素赋值,那么就会使用默认值[int, float => 0 string => “ ” bool => false]
    3)通过make方式创建的切片对应的数组是由make底层维护,对外不可见,即只能通过slice去访问各个元素
    
    方式3:定义一个切片,直接就指定具体数组,使用原理类似make的方式
    func main() {
       var strSlice []string = []string {"zisefeizhu","zhujingxing","mayike"}
       fmt.Println("strSlice = ", strSlice)
       fmt.Println("strSlice size = ",len(strSlice))
       fmt.Println("strSlice cap = ",cap(strSlice))
    }
    //输出:strSlice =  [zisefeizhu jingxing mayike]
    //strSlice size =  3
    //strSlice cap =  3
    
    方式1和方式2的区别(面试)
    	方式1是直接引用数组,这个数组是事先存在的,程序员是可见的
    	方式2是通过make来创建切片,make也会创建一个数组,是由切片在底层进行维护,程序员是看不见的,make创建切片的示意图
    

    切片的遍历

    func main()  {
       //使用常规的for循环遍历切片
       var arr [5]int = [...]int {10, 20, 30, 40, 50}
       slice := arr[1:4] // 20, 30, 40
       for i := 0; i < len(slice); i++ {
          fmt.Printf("slice[%v] = %v 	",i , slice[i])
       }
       fmt.Println()
    
       //使用for - range 方式遍历切片
       for i, v := range slice {
          fmt.Printf("i = %v v = %v 
    ",i ,v)
       }
    }
    

    切片使用的注意事项和细节

    slice扩充缩容会有内存申请释放也是开销,且扩容好像是1.25倍
    切片初始化时 var slice = arr[startIndex:endIndex]
    	说明:从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex])
    切片初始化时,仍然不能越界。范围在[0 - len(arr)]之间,但是可以动态增长
    	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一个空间供切片来使用
    切片可以继续切片
    	func main()  {
       	var arr [5]int = [...]int {10, 20, 30, 40, 50}
       	slice := arr[1:4] // 20, 30, 40
       	slice2 := slice[1:2] // slice [20,30,40] [30]
       	slice2[0] = 100 //因为arr slice 和slice2 指向的数据空间是一个,因此slice2[0] =100
       	fmt.Println("slice2 = ",slice2)
       	fmt.Println("slice = ",slice)
       	fmt.Println("arr = ",arr)
    	}
    append内置函数,可以对切片进行动态追加
    	func main()  {
      	 //用append内置函数,可以对切片进行动态追加
       	var slice []int = []int {100,200,300}
       	//通过append直接给slice追加具体的元素
       	slice = append(slice,400,500,600)
      	fmt.Println("slice",slice) //100, 200, 300, 400, 500, 600
       	//通过append将切片slice 追加给slice
       	slice = append(slice,slice...)   
      	fmt.Println("slice",slice) ////slice [100 200 300 400 500 600 100 200 300 400 500 600]
      }
    	切片append操作的底层原理分析
    		切片append操作的本质就是对数组扩容
    		go底层会创建一下新的数组newArr(安装扩容后大小)
    		将slice原来包含的元素拷贝到新的数组newArr
    		slice 重新引用到newArr
    		注意newArr是在底层来维护的,程序员不可见
    

    切片的拷贝操作
    	切片使用copy内置函数完成拷贝,举例说明
    	func main()  {
       	//切片的拷贝操作
       	//切片使用copy内置函数完成拷贝,举例说明
       	var slice []int = []int {1,2,3,4,5}
       	var slice2 = make([]int,10)
       	copy(slice2,slice)
       	fmt.Println("slice = ",slice)  //slice =  [1 2 3 4 5]
       	fmt.Println("slice2 = ",slice2) //slice2 =  [1 2 3 4 5 0 0 0 0 0]
    	}
    	copy(para1,para2)参数的数据类型是切片
    	按照上面的代码来看,slice和slice2的数据空间是独立,相互不影响,也就是说slice[0] = 999,slice5[0] 仍然是1
    关于拷贝的注意事项
    	func main()  {
       	var a []int = []int {1,2,3,4,5}
       	var slice = make([]int,1)
       	fmt.Println(slice)
       	copy(slice,a)
       	fmt.Println(slice)
    	}
    	//输出:[0]
    	//[1]	
    切片是引用类型,所以在传递时,遵守引用传递机制。看两段代码,并分析底层原理
    

    string和slice

    string底层是一个byte数组,因此string也可以进行切片处理

    func main(){
       str := "hello@zisefeizhu"
       //使用切片获取到zisefeizhu
       slice := str[6:]
       fmt.Println("slice = ",slice)
    }
    //输出:slice =  zisefeizhu
    

    string和切片在内存的形式,以”abcd”画出内存示意图

    string是不可变的,也就是说不能通过str[0] = ‘z’ 方式来修改字符串

    如果需要修改字符串,可以先将string -> []byte /或者 []rune -> 修改 -> 重写转成string

    如果需要修改字符串,可以先将string -> []byte  /或者  []rune -> 修改 -> 重写转成string
       //"hello@zisefeizhu" => 改成 "zello@zisefeizhu"
       arr1 := []byte(str)
       arr1[0] = 'z'
       str = string(arr1)
       fmt.Println("str = ",str)
       //细节:我们转成[]byte后,可以处理英文和数字,但是不能处理中文
       //原因是[]byte字节来处理,而一个汉字,是3个字节,因此就会出现乱码
       //解决方法是 将 string 转成 []rune 即可,因为[]rune 是按字符处理,兼容汉字
       arr2 := []rune(str)
       arr2[0] = '北'
       str = string(arr1)
       fmt.Println("str = ", str)
    }
    //输出:slice =  zisefeizhu
    //str =  zello@zisefeizhu
    //str =  zello@zisefeizhu
    

    切片练习题

    说明:编写一个函数 fbn(n int),要求完成

    1. 可以接收一个n int

    2. 能够将斐波那契的数列放到切片中

    3. 提示,斐波那契的数列形式:

    arr[0] = 1; arr[1] = 1; arr[2] = 2; arr[3] = 3; arr[4] = 5; arr[5] = 8

    package main
    
    import "fmt"
    
    func fbn(n int) ([]uint64) {
       //声明一个切片,切片大小n
       fbnSlice := make([]uint64, n)
       //第一个数和第二个数的斐波那契为 1
       fbnSlice[0] = 1
       fbnSlice[1] = 1
       //进行for循环来存放斐波那契的数列
       for i := 2; i < n; i++ {
          fbnSlice[i] = fbnSlice[i - 1] + fbnSlice[i - 2]
       }
       return fbnSlice
    }
    func main()  {
       /*
       1)可以接收一个n int
       2)能够将斐波那契的数列放到切片中
       3)提示,斐波那契的数列形式:
       arr[0] = 1; arr[1] = 1; arr[2] = 2; arr[3] = 3; arr[4] = 5; arr[5] = 8
       思路
       1. 声明一个函数fbn(n int) ([]uint64)
       2. 编程fbn(n int) 进行for循环来存放斐波那契的数列 0 =》1  1 =》 1
        */
       fnbSlice := fbn(20)
       fmt.Println("fnbSlice = ",fnbSlice)
    }
    //输出:fnbSlice =  [1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765]
    

    排序

    排序

    排序是将一组数据,依指定的顺序进行排序的过程

    排序的分类
    1)内部排序:
    	指将需要处理的所有数据都加载到内部存储器中进行排序
    	包括(交换式排序法、选择式排序法和插入式排序法);
    2)外部排序法
    	数据量过大,无法全部加载到内存中,需要借助外部存储进行排序
    	包括(合并排序法和直接合并排序法)
    

    冒泡排序的思路分析


    冒泡排序实现

    //冒泡排序
    func BubbleSort(arr *[5]int)  {
       fmt.Println("排序前arr = ",(*arr))
       temp := 0 //临时变量(用于做交换)
    
       //冒泡排序:一步一步推导出来的
       for i := 0; i < len(*arr) - 1; i++ {
          for j := 0; j < len(*arr) -1 - i; j++ {
             if (*arr)[j] < (*arr)[j + 1] {
                //交换
                temp = (*arr)[j]
                (*arr)[j] = (*arr)[j + 1]
                (*arr)[j + 1] = temp
             }
          }
       }
       fmt.Println("排序后arr  = ",(*arr))
    }
    func main()  {
       //定义数组
       arr := [...]int {24,69,80,57,13}
       //将数组传递给一个函数,完成排序
       BubbleSort(&arr)
       fmt.Println("main arr = ",arr) //有序? 是有序的
    }
    //输出:排序前arr =  [24 69 80 57 13]
    //排序后arr  =  [80 69 57 24 13]
    //main arr =  [80 69 57 24 13]
    
    优化
    //冒泡排序
    func BubbleSort(arr []int) []int {
       fmt.Println("排序前arr = ", arr)
       flag := true
       //冒泡排序:一步一步推导出来的
       for i := 0; i < len(arr) - 1; i++ {
          for j := 0; j < len(arr) -1 - i; j++ {
             if arr[j] < arr[j + 1] {
                //交换
                Swap(arr, j , j+1)
                flag = false
             }
          }
          //优化不必要的交换
          if flag {
             break
          }
       }
       return arr
    }
    
    func Swap(arr []int, i int, j int )  {
       temp := arr[i]
       arr[i] = arr[j]
       arr[j] = temp
    }
    
    func main()  {
       //定义数组
       arr := []int {24,69,80,57,13}
       //将数组传递给一个函数,完成排序
       num := BubbleSort(arr)
       fmt.Println("main num = ",num)
    }
    //排序前arr =  [24 69 80 57 13]
    //main num =  [80 69 57 24 13]
    

    冒泡排序练习题

    package main
    //要求:随机生成5个元素的数组,并使用冒泡排序对其排序  从小到大
    //思路分析:
    //随机数用math/rand生成为了更好的保证其不会重复 使用 rand.New(rand.NewSource(time.Now().UnixNano()))并定义一个随机生成函数
    //用冒泡排序对其排序
    import (
       "fmt"
       "math/rand"
       "time"
    )
    
    var  arrnum [5]int = [5]int{109,137,49,190,87}
    //定义冒泡函数
    //重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)
    // 错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成
    func BubbleSort( arrary *[5]int){
       //第一次比较
       fmt.Println("排序前arr=",(*arrary))
       tmp :=0
       for  j := 0 ; j <len(arrary)-1 ;j++{
          for  i :=0;i <len(arrary)-1-j ;i++ {
             if arrary[i] > arrary[i+1]{
                tmp = arrary[i]
                arrary[i] = arrary[i+1]
                arrary[i+1] = tmp
             }
          }
       }
    
       fmt.Println("排序后arr=",(*arrary))
    
    }
    
    
    var  Arrname  [5]int
    
    func main() {
       r := rand.New(rand.NewSource(time.Now().UnixNano()))//生成随机数字
       for  i := 0; i < len(Arrname) ; i++ {
          Arrname[i] = r.Intn(20000) //指定生成随机数的范围
       }
       BubbleSort(&Arrname)
    
    }
    

    查找

    在Go中,常用的查找有两种:

    1. 顺序查找

    2. 二分查找(该数组是有序)

    案例演示

    1)有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王

    猜数游戏:从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】

    func main()  {
       names := [4]string{"白眉鹰王","金毛狮王","紫衫龙王","青翼蝠王"}
       var heroName = ""
       fmt.Println("请输入要查找的人名...")
       fmt.Scanln(&heroName)
       //顺序查找:第一种方式
       for i := 0; i < len(names); i++ {
          if heroName == names[i] {
             fmt.Printf("找到%v 下标%v 
    ",heroName,i)
             break
          } else if i == (len(names) -1 ) {
             fmt.Printf("没有找到%v 
    ",heroName)
          }
       }
    
       //顺序查找:第二种方式【推荐...】
       index := -1
       for i := 0; i < len(names); i++ {
          if heroName == names[i] {
             index = i //将找到的值对应的下标赋给index
             break
          }
       }
       if index != -1 {
          fmt.Printf("找到%v,下标%v 
    ",heroName,index)
       } else {
          fmt.Println("没有找到",heroName)
       }
    }
    //输出:请输入要查找的人名...  白眉鹰王   找到白眉鹰王 下标0   找到白眉鹰王,下标0 
    
    1. 请对一个有序数组进行二分查找 {1,8,10,89,1000,1234},输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示”没有这个数”【会使用到递归】

    二分查找的思路分析

    //二分法查找
    /*
       二分查找思路:比如要查找的数是findVal
       1. arr是一个有序数组,并且是从小到大排序
       2. 先找到中间的下标middle = (leftIndex + rightIndex)/2,然后让中间下标的值和findVal进行比较
       2.1  如果arr[middle] > findVal  就应该向 leftIndex --- (middle - 1)
       2.2  如果arr[middle] < findVal  就应该向 (middle + 1) --- rightIndex
       2.3  如果arr[middle] == findVal  就找到
       2.4  上面的2.1 2.2 2.3 的逻辑会递归执行
       3. 想一下,怎么样的情况下,就说明找不到【分析出退出递归的条件!!】
       if leftIndex > rightIndex {
          //找不到...
          return ...
       }
     */
    
    func BinaryFind(arr *[6]int, leftIndex int, rightIndex int, findVal int)  {
       //判断leftIndex是否大于rightIndex
       if leftIndex > rightIndex {
          fmt.Println("找不到")
          return
       }
       //先找到 中间的下标
       middle := (leftIndex + rightIndex) / 2
       if (*arr)[middle] > findVal {
          //说明要查找的数,应该在leftIndex -- (middle - 1)
          BinaryFind(arr, leftIndex, middle - 1, findVal)
       } else if (*arr)[middle] < findVal {
          //说明要查找的数,应该在middle + 1 -- rightIndex
          BinaryFind(arr, middle + 1, rightIndex, findVal)
       } else {
          //找到了
          fmt.Printf("找到了,下标为%v 
    ",middle)
       }
    }
    func main()  {
       arr := [6]int {1,8,89,1000,1234}
       //测试
       BinaryFind(&arr,0,len(arr) - 1, 1234)
    }
    //输出:找到了,下标为4 
    

    二维数组

    请用二维数组输出如下图形

    func main()  {
       //定义/声明二维数组
       var arr [4][6]int
       //赋初值
       arr[1][2] = 1
       arr[2][1] = 2
       arr[2][3] = 3
       //遍历二维数组,按照要求输出图形
       for i := 0; i < 4; i++ {
          for j := 0; j < 6; j++ {
             fmt.Print(arr[i][j]," ")
          }
          fmt.Println()
       }
    }
    //0 0 0 0 0 0 
    //0 0 1 0 0 0 
    //0 2 0 3 0 0 
    //0 0 0 0 0 0 
    

    二维数组在内存的存在形式

    二维数组在声明/定义时的写法

    1)var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值...},{初值...}}
    2)var 数组名 [大小][大小]类型 = [...][大小]类型{{初值...},{初值...}}
    3)var 数组名  = [大小][大小]类型{{初值...},{初值...}}
    4)var 数组名 = [...][大小]类型{{初值...},{初值...}}
    

    二维数组的遍历

    func main()  {
       //演示二维数组的遍历
       var arr = [2][3]int{{1,2,3},{4,5,6}}
       //for循环遍历
       for i := 0; i < len(arr); i++ {
          for j := 0; j < len(arr[i]); j++ {
             fmt.Printf("%v	",arr[i][j])
          }
          fmt.Println()
       }
       //for-range遍历二维数组
       for i, v := range arr {
          for j, v2 := range v {
             fmt.Printf("arr[%v][%v]=%v	",i,j,v2)
          }
          fmt.Println()
       }
    }
    

    二维数组的应用案例

    定义二维数组,用于保存三个班,每个班五名同学成绩,

    并求出每个班级平均分、以及所有班级平均分

    func main()  {
       //定义二维数组,用于保存三个班,每个班五名同学成绩,
       //并求出每个班级平均分、以及所有班级平均分
       //1.定义二维数组
       var scores [3][5]float64
       //2.循环的输入成绩
       for i := 0; i < len(scores); i++ {
          for j := 0; j < len(scores[i]); j++ {
             fmt.Printf("请输入第%d班的第%d个学生的成绩
    ",i+1, j+1)
             fmt.Scanln(&scores[i][j])
          }
       }
       //fmt.Println(scores)
       //3.遍历输出成绩后的二维数组,统计平局分
       totalSum := 0.0 //定义一个变量,用于累计所有班级的总分
       for i := 0; i < len(scores); i++ {
          sum := 0.0 //定义一个变量,用于累计各个班级的总分
          for j := 0; j < len(scores[i]); j++ {
             sum += scores[i][j]
          }
          totalSum += sum
          fmt.Printf("第%d班级的总分为%v,平均分%v
    ", i + 1, sum, sum / float64(len(scores[i])))
       }
       fmt.Printf("所有班级的总分为%v,所有班级平均分%v
    ", totalSum, totalSum / 15 )
    }
    

    二维数组练习题

    转置概念:矩阵的行列互换得到的新矩阵称为转置矩阵,而二维数组就是我们通常说的矩阵。

    需求:使用Go语言方法实现二维数组(3*3)的矩阵的转置

    转置前:

    ​ [ 0, 1, 2]

    ​ [ 4, 5, 6]

    ​ [ 8, 9, 10]

    转置后

    ​ [ 0, 4, 8]

    ​ [ 1, 5, 9]

    ​ [ 2, 6, 10]

    type   Num struct {
    
    }
    
    func (array  Num ) Upserver(Aaaay3 [3][3]int)  {
       for i :=0; i<len(Aaaay3);i++{
          for  j:=0;j<i;j++{
             Aaaay3[i][j],Aaaay3[j][i] = Aaaay3[j][i],Aaaay3[i][j]
          }
       }
       fmt.Println(Aaaay3)
    }
    
    func (array  Num ) Upserver2(Aaaay3 [3][3]int)  {
       temparry :=[3][3]int{}
       for i :=0; i<len(Aaaay3);i++{
          for  j:=0;j<i;j++{
             temparry[i][j]=Aaaay3[i][j]
             Aaaay3[i][j] =Aaaay3[j][i]
             Aaaay3[j][i]=temparry[i][j]
          }
       }
       fmt.Println(Aaaay3)
    }
    
    func main() {
       arrinfo :=Num{
    
       }
       aeey :=[3][3]int{
          {0, 1, 2} ,   /*  第一行索引为 0 */
          {4, 5, 6} ,   /*  第二行索引为 1 */
          {8, 9, 10}}
       fmt.Println(aeey)
       fmt.Println("****")
       arrinfo.Upserver(aeey)
       arrinfo.Upserver2(aeey)
    }
    

    Map

    map是key-value数据结构,又称为字段或者关联数组。类似其它编程语言的集合,在编程中是经常使用到的

    v 内部实现

    Map是给予散列表来实现,就是我们常说的Hash表,所以我们每次迭代Map的时候,打印的Key和Value是无序的,每次迭代的都不一样,即使我们按照一定的顺序存在也不行。

    Map的散列表包含一组桶,每次存储和查找键值对的时候,都要先选择一个桶。如何选择桶呢?就是把指定的键传给散列函数,就可以索引到相应的桶了,进而找到对应的键值。

    这种方式的好处在于,存储的数据越多,索引分布越均匀,所以我们访问键值对的速度也就越快,当然存储的细节还有很多,大家可以参考Hash相关的知识,这里我们记住Map存储的是无序的键值对集合

    map的声明

    var 变量名 map[keytype]valuetype
    key可以是什么类型
    	Go中的map的key可以是很多种类型,比如bool、数字、string、指针、channel,还可以是只包含前面几个类型的 接口、结构体、数组
    	通常key为int、string
    	注意:slice、map还有function不可以,因为这几个没法用 == 来判断
    valuetype可以是什么类型
    	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,分配内存后才能赋值和使用
    
    func main()  {
       //map的声明和注意事项
       var a map[string]string
       //在使用map前,需要先make,make的作用就是给map分配数据空间
       a = make(map[string]string,10)
       a["no1"] = "松江"
       a["no2"] = "无用"
       a["no1"] = "武松"
       a["no3"] = "无用"
       fmt.Println(a)
    }
    //输出:map[no1:武松 no2:无用 no3:无用]
    对上面代码的说明
    	1)map在使用前一定要make
    	2)map的key是不能重复的,如果重复了,则以最后这个key-value为准
    	3)map的value是可以相同的
    	4)map的key-value是无序的
    	5)make内置函数数目
    

    map的使用

    方式1:
    func main()  {
       //第一种使用方式
       var a map[string]string
       //在使用map前,需要先make,make的作用就是给map分配数据空间
       a = make(map[string]string,10)
       a["no1"] = "松江"
       a["no2"] = "无用"
       a["no1"] = "武松"
       a["no3"] = "无用"
       fmt.Println(a)
    }
    
    方式2:
    func main()  {
       //第二种方式
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       fmt.Println(cities)
    //输出:map[no1:北京 no2:天津 no3:上海]
      
    方式3:
    func main()  {
    	//第三种方式
    	heroes := map[string]string {
    		"her01" : "宋江",
    		"her02" : "吴用",
    		"her03" : "林冲",
    	}
    	heroes["her04"] = "武松"
    	fmt.Println("heroes = ",heroes)
    }
    //heroes =  map[her01:宋江 her02:吴用 her03:林冲 her04:武松] 
    

    map的增删改查操作

    map增加和更新
    map["key"] = value //如果key还没有,就是增加,如果key存在就是修改

    func main(){
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       fmt.Println(cities)
       //因此no3 这个key已经存在,因此下面的这句就是修改
       cities["no3"] = "上海~"
       fmt.Println(cities)
    }
    //输出:map[no1:北京 no2:天津 no3:上海]
    //map[no1:北京 no2:天津 no3:上海~]
    

    map删除

    delete(map,"key"),delete是一个内置函数,如果key存在,就删除该key-value,如果key不存在,不操作,但是也不会报错

    func main(){
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
       //因此no3 这个key已经存在,因此下面的这句就是修改
       cities["no3"] = "上海~"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
       //演示删除
       delete(cities,"no1")
       fmt.Println(cities)  //map[no2:天津 no3:上海~]
       //当delete指定的key不存在时,删除不会操作,也不会报错
       delete(cities,"no4")
       fmt.Println(cities)  //map[no2:天津 no3:上海~]
      
    如果要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,逐个删除或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收
    func main(){
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
       //因此no3 这个key已经存在,因此下面的这句就是修改
       cities["no3"] = "上海~"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
       //演示删除
       delete(cities,"no1")
       fmt.Println(cities)  //map[no2:天津 no3:上海~]
       //当delete指定的key不存在时,删除不会操作,也不会报错
       delete(cities,"no4")
       fmt.Println(cities)  //map[no2:天津 no3:上海~]
       //如果希望一次性删除所有的key
       //1. 遍历所有的key,遍历逐一删除
       //2. 直接make一个新的空间
       cities = make(map[string]string)
       fmt.Println(cities)  //map[]
    }  
    

    map查找

    func main(){
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海]
       //因此no3 这个key已经存在,因此下面的这句就是修改
       cities["no3"] = "上海~"
       fmt.Println(cities)  //map[no1:北京 no2:天津 no3:上海~]
       //演示map 的查找
       va1, ok := cities["no2"]
       if ok {
          fmt.Printf("有no2 key值为%v
    ",va1)  //有no2 key值为天津
       } else {
          fmt.Printf("没有no2 key
    ")
       }
    }
    
    对上面代码的说明:
    说明:如果cities这个map中存在”no2”,那么ok就会返回true,否则返回false
    

    map遍历

    案例演示相对复杂的map遍历:该map的value又是一个map

    说明:map的遍历使用for-range的结构遍历

    func main()  {
       //使用for-range遍历map
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       for k,v := range cities {
          fmt.Printf("k = %v v = %v
    ",k,v)
       }
       //使用for-range遍历一个结构比较复杂的map
       studentMap := make(map[string]map[string]string)
       studentMap["stu01"] = make(map[string]string, 3)
       studentMap["stu01"]["name"] = "tom"
       studentMap["stu01"]["sex"] = "男"
       studentMap["stu01"]["address"] = "北京长安街"
    
       studentMap["stu02"] = make(map[string]string, 3)  //这句话不能少!!!
       studentMap["stu02"]["name"] = "mary"
       studentMap["stu02"]["sex"] = "女"
       studentMap["stu02"]["address"] = "上海黄埔江"
    
       for k1, v1 := range studentMap {
          fmt.Println("k1 = ",k1)
          for  k2, v2 := range v1 {
             fmt.Printf("	 k2 = %v v2 = %v 
    ",k2,v2)
          }
          fmt.Println()
       }
    }
    //输出:k = no1 v = 北京
    //k = no2 v = 天津
    //k = no3 v = 上海
    //k1 =  stu01
    //  k2 = name v2 = tom 
    //  k2 = sex v2 = 男 
    //  k2 = address v2 = 北京长安街 
    //
    //k1 =  stu02
    //  k2 = name v2 = mary 
    //  k2 = sex v2 = 女 
    //  k2 = address v2 = 上海黄埔江 
    

    map的长度

    func main()  {
       //使用for-range遍历map
       cities := make(map[string]string)
       cities["no1"] = "北京"
       cities["no2"] = "天津"
       cities["no3"] = "上海"
       for k,v := range cities {
          fmt.Printf("k = %v v = %v
    ",k,v)
       }
       fmt.Println(len(cities))  //3
    }
    

    map切片

    切片的数据类型如果是map,则我们称为slice of map,map切片,这样使用则map个数就可以动态变化了

    案例演示

    要求:使用一个map来记录monster的信息name和age,也就是说一个monster对应一个map,并且妖怪的个数可以动态的增加=》map切片

    package main
    
    import (
       "fmt"
       _ "unicode"
    )
    
    func main()  {
       var monsters []map[string]string
       monsters = make([]map[string]string,2) //准备放入两个妖怪
       //2. 增加第一个妖怪的信息
       if monsters[0] == nil {
          monsters[0] = make(map[string]string,2)
          monsters[0]["name"] = "牛魔王"
          monsters[0]["age"] = "500"
       }
    
       if monsters[1] == nil {
          monsters[1] = make(map[string]string, 2)
          monsters[1]["name"] = "玉兔精"
          monsters[1]["age"] = "400"
       }
       //下面这个写法越界
       //if monsters[2] == nil {
       //    monsters[2] = make(map[string]string, 2)
       //    monsters[2]["name"] = "狐狸精"
       //    monsters[2]["age"] = "300"
       // }
    
       //这里需要使用到切片的append函数,可以动态的增加monster
       //1. 先定义monster信息
       newMonster := map[string]string {
          "name" : "新的妖怪-孙悟空",
          "age" : "1500",
       }
       monsters = append(monsters,newMonster)
    
       fmt.Println(monsters)
    }
    //输出:[map[age:500 name:牛魔王] map[age:400 name:玉兔精] map[age:1500 name:新的妖怪-孙悟空]]
    

    map排序

    Go中没有一个专门的方法针对map的key进行排序

    Go中的map默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的输出可能不一样

    Go中map的排序,是先将key进行排序,然后根据key值遍历输出即可

    案例演示

    package main
    
    import (
       "fmt"
       "sort"
    )
    func main()  {
       //map的排序
       map1 := make(map[int]int,10)
       map1[10] = 100
       map1[1] = 13
       map1[4] = 56
       map1[8] = 90
       fmt.Println(map1)
       //如果按照map的key的顺序进行排序输出
       //1. 先将map的key放入到切片中
       //2. 对切片排序
       //3. 遍历切片,然后按照key来输出map的值
       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 
    ", k, map1[k])
       }
    }
    //输出:map[1:13 4:56 8:90 10:100]
    //[1 4 8 10]
    //map1[1] = 13 
    //map1[4] = 56 
    //map1[8] = 90 
    //map1[10] = 100 
    

    map使用细节

    map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map

    func modify(map1 map[int]int)  {
       map1[10] = 900
    }
    func main()  {
       map1 := make(map[int]int)
       map1[1] = 90
       map1[2] = 88
       map1[10] = 1
       map1[20] = 2
       modify(map1)
       fmt.Println(map1)
    }
    //输出:map[1:90 2:88 10:900 20:2]
    

    map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长 键值对(key-value)

    map的value也经常使用struct类,更适合管理复杂的数据(比前面value是一个map更好),比如value为Student结构体

    type Stu struct {
    	Name  string
    	Age   int
    	Address  string
    }
    
    func main()  {
    	//3)map的value也经常使用struct类型,
    	// 更适合管理复杂的数据(比前面value是一个map更好),
    	// 比如value为Student结构体
    	//1. map 的 key 为学生的学号,是唯一的
    	//2. map的value 为结构体,包含学生的名字,年龄,地址
    	students := make(map[string]Stu, 10)
    	//创建2个学生
    	stu1 := Stu{"tom", 18, "北京"}
    	stu2 := Stu{"mary", 28, "上海"}
    	students["no1"] = stu1
    	students["no2"] = stu2
    
    	fmt.Println(students)
    	//遍历各个学生信息
    	for k, v := range students {
    		fmt.Printf("学生的编号是%v 
    ",k)
    		fmt.Printf("学生的名字是%v 
    ",v.Name)
    		fmt.Printf("学生的年龄是%v 
    ",v.Age)
    		fmt.Printf("学生的地址是%v 
    ",v.Address)
    	}
    }
    //map[no1:{tom 18 北京} no2:{mary 28 上海}]
    //学生的编号是no1
    //学生的名字是tom
    //学生的年龄是18
    //学生的地址是北京
    //学生的编号是no2
    //学生的名字是mary
    //学生的年龄是28
    //学生的地址是上海 
    

    map练习题

    演示一个key-value的value是map的案例

    ​ 比如:要存放3个学生信息,每个学生有name和sex信息

    ​ 思路: map[string]map[string]string

    func main()  {
       studentMap := make(map[string]map[string]string)
       studentMap["stu01"] = make(map[string]string, 3)
       studentMap["stu01"]["name"] = "tom"
       studentMap["stu01"]["sex"] = "男"
       studentMap["stu01"]["address"] = "北京长安街"
    
       studentMap["stu02"] = make(map[string]string, 3)  //这句话不能少!!!
       studentMap["stu02"]["name"] = "mary"
       studentMap["stu02"]["sex"] = "女"
       studentMap["stu02"]["address"] = "上海黄埔江"
    
       fmt.Println(studentMap)  //map[stu01:map[address:北京长安街 name:tom sex:男] stu02:map[address:上海黄埔江 name:mary sex:女]]
       fmt.Println(studentMap["stu02"])  //map[address:上海黄埔江 name:mary sex:女]
       fmt.Println(studentMap["stu02"]["address"])  //上海黄埔江
    }
    

    编写一个函数modifyUser(users map[string]map[string]string,name string)完成上下述功能

    1. 使用map[string]map[string]string的map类型

    2. key:表示用户名,是唯一的,不可以重复

    3. 如果某个用户存在,就将其密码修改"888888",如果不存在就增加这个用户信息(包括昵称nickname和密码pwd)。

    func modifyUser(users map[string]map[string]string,name string)  {
       //判断users中是否有name
       //v,ok := users[name]
       if users[name] != nil {
          //有这个用户
          users[name]["pwd"] = "888888"
       } else {
          //没有这个用户
          users[name] = make(map[string]string,2)
          users[name]["pwd"] = "888888"
          users[name]["nickname"] = "昵称~" + name //示意
       }
    }
    func main()  {
       users := make(map[string]map[string]string,10)
       users["smith"] = make(map[string]string,2)
       users["smith"]["pwd"] = "999999"
       users["smith"]["nickname"] = "小花猫"
    
       modifyUser(users,"tom")
       modifyUser(users,"mary")
       modifyUser(users,"smith")
       fmt.Println(users)
    }
    //输出:map[mary:map[nickname:昵称~mary pwd:888888] smith:map[nickname:小花猫 pwd:888888] tom:map[nickname:昵称~tom pwd:888888]]
    
  • 相关阅读:
    现代软件工程第一次结对编程(黄金点游戏)总结
    现代软件工程第一周博客作业
    最后一周总结
    阅读和提问作业3 (期中作业)
    软件工程作业 案例分析
    第二次结对编程
    现代软件工程 结对编程总结
    现代软件工程 第一周 博客作业
    阅读作业
    Judy Beta 第三天
  • 原文地址:https://www.cnblogs.com/zisefeizhu/p/12628336.html
Copyright © 2020-2023  润新知