5.2 Go 数组进阶学习笔记(多维、排序、搜索) 5.2 Go 数组进阶学习笔记多维、排序、搜索1. 多维数组 — 声明与访问多维数组是数组的数组Go 通过[行][列]语法定义packagemainimportfmtfuncmain(){// 声明 3x3 矩阵元素全部为零值 0varmatrix[3][3]int// 初始化 2x4 数组2行4列grades:[2][4]int{{85,92,78,96},{88,91,84,87}}// 修改元素matrix[行][列]matrix[1][1]5// 第2行第2列设为5// 打印矩阵嵌套 for 循环fmt.Println(Matrix:)fori:0;ilen(matrix);i{forj:0;jlen(matrix[i]);j{fmt.Printf(%3d ,matrix[i][j])// %3d 右对齐宽度3}fmt.Println()// 每行末尾换行}}执行结果Matrix: 0 0 0 0 5 0 0 0 0要点[3][3]int— 3x3 的二维数组类型是3个[3]int的数组var matrix [3][3]int— 未初始化所有元素为零值 0matrix[1][1] 5— 先选行索引1再选列索引1设为5len(matrix) 3行数len(matrix[i]) 3每行的列数%3d— 右对齐宽度3保证矩阵格式整齐0、5Go 没有专门的矩阵类型多维数组就是数组的数组2. 多维数组 — range 遍历与统计用嵌套 range 遍历多维数组更简洁packagemainimportfmtfuncmain(){grades:[2][4]int{{85,92,78,96},{88,91,84,87}}// range 遍历外层遍历行内层遍历每行的元素fmt.Println(Grades:)fori,row:rangegrades{fmt.Printf(Student %d: ,i1)for_,grade:rangerow{fmt.Printf(%d ,grade)}fmt.Println()}// 求所有元素总和嵌套 for 循环vartotalSumintfori:0;ilen(grades);i{forj:0;jlen(grades[i]);j{totalSumgrades[i][j]}}fmt.Println(Total sum of grades:,totalSum)// 获取维度行数 × 列数rows:len(grades)varcolsintifrows0{colslen(grades[0])}fmt.Printf(Grades array dimensions: %dx%d\n,rows,cols)}执行结果Grades: Student 1: 85 92 78 96 Student 2: 88 91 84 87 Total sum of grades: 701 Grades array dimensions: 2x4要点for i, row : range grades—row是一整行类型[4]inti是行号for _, grade : range row— 遍历每行的每个成绩求和嵌套 for 遍历所有元素grades[i][j]用双重索引访问维度len(grades) 行数 2len(grades[0]) 列数 4注意grades的类型是[2][4]int所以所有行的列数固定为4数组长度是类型的一部分3. 数组排序 — sort 包Go 的sort包提供排序函数但只能对切片排序需要用[:]把数组转为切片packagemainimport(fmtsort)funcmain(){numbers:[5]int{64,34,25,12,22}names:[4]string{Charlie,Alice,Bob,David}prices:[6]float64{19.99,9.99,29.99,4.99,39.99,14.99}fmt.Println(Before sorting:)fmt.Println(Numbers:,numbers)fmt.Println(Names:,names)fmt.Println(Prices:,prices)// sort.Ints() 排序 int 切片升序sort.Ints(numbers[:])// numbers[:] 把数组转为切片// sort.Strings() 排序 string 切片升序sort.Strings(names[:])// sort.Float64s() 排序 float64 切片升序sort.Float64s(prices[:])fmt.Println(\nAfter sorting:)fmt.Println(Numbers:,numbers)fmt.Println(Names:,names)fmt.Println(Prices:,prices)// 检查是否已排序isSorted:sort.IntsAreSorted(numbers[:])fmt.Println(Numbers array is sorted:,isSorted)}执行结果Before sorting: Numbers: [64 34 25 12 22] Names: [Charlie Alice Bob David] Prices: [19.99 9.99 29.99 4.99 39.99 14.99] After sorting: Numbers: [12 22 25 34 64] Names: [Alice Bob Charlie David] Prices: [4.99 9.99 14.99 19.99 29.99 39.99] Numbers array is sorted: true要点sort.Ints(numbers[:])—numbers[:]把[5]int数组转为[]int切片切片引用数组的底层内存排序后数组本身也被修改了因为切片和数组共享同一块内存sort.Ints— int 升序排序sort.Strings— string 按字典序sort.Float64s— float64 升序sort.IntsAreSorted(numbers[:])— 检查切片是否已排序返回 bool数组不能直接排序sort.Ints(numbers)编译报错必须转为切片4. 逆序排序 — sort.Reversesort.Sort(sort.Reverse(sort.IntSlice(slice)))实现降序排序packagemainimport(fmtsort)funcmain(){descNumbers:[5]int{1,2,3,4,5}fmt.Println(Before reverse sort:,descNumbers)// 降序排序sort.Sort sort.Reverse sort.IntSlicesort.Sort(sort.Reverse(sort.IntSlice(descNumbers[:])))fmt.Println(After reverse sort:,descNumbers)}执行结果Before reverse sort: [1 2 3 4 5] After reverse sort: [5 4 3 2 1]要点sort.IntSlice(descNumbers[:])— 把切片包装为IntSlice类型实现 sort.Interface 接口sort.Reverse(...)— 反转排序顺序把升序变为降序sort.Sort(...)— 执行自定义排序三层包装sort.Sort(sort.Reverse(sort.IntSlice(slice)))同理sort.Reverse(sort.StringSlice(slice))— string 降序sort.Reverse(sort.Float64Slice(slice))— float64 降序排序同样修改原数组切片与数组共享内存5. 线性搜索 — 逐个遍历查找线性搜索从头到尾逐个比较适用于未排序的数组时间复杂度 O(n)packagemainimportfmtfuncmain(){numbers:[10]int{64,34,25,12,22,11,90,88,76,50}target:22foundIndex:-1// -1 表示未找到fori,value:rangenumbers{ifvaluetarget{foundIndexibreak// 找到后立即退出}}iffoundIndex!-1{fmt.Printf(Linear search: Found %d at index %d\n,target,foundIndex)}else{fmt.Printf(Linear search: %d not found\n,target)}}执行结果Linear search: Found 22 at index 4要点foundIndex -1— 用 -1 表示未找到索引不会是负数range numbers遍历每个元素value target比较是否匹配break— 找到目标后立即停止遍历不必检查剩余元素线性搜索适用于任何数组排序或未排序但效率较低n 个元素最多比较 n 次Go 没有内置的线性搜索函数需要手动实现6. 二分搜索 — sort.SearchInts二分搜索只在已排序数组上有效时间复杂度 O(log n)packagemainimport(fmtsort)funcmain(){sortedNumbers:[8]int{5,12,23,34,45,67,78,89}binaryTarget:45// sort.SearchInts 在已排序切片中查找目标binaryIndex:sort.SearchInts(sortedNumbers[:],binaryTarget)// 必须验证SearchInts 返回的可能是应插入的位置而非找到的位置ifbinaryIndexlen(sortedNumbers)sortedNumbers[binaryIndex]binaryTarget{fmt.Printf(Binary search: Found %d at index %d\n,binaryTarget,binaryIndex)}else{fmt.Printf(Binary search: %d not found\n,binaryTarget)}}执行结果Binary search: Found 45 at index 4要点sort.SearchInts(sortedNumbers[:], 45)— 在已排序切片中二分查找返回值含义如果找到返回目标索引如果未找到返回目标应插入的位置所以必须验证binaryIndex len(sortedNumbers) sortedNumbers[binaryIndex] binaryTarget如果不验证未找到时也会返回一个索引插入位置可能误判为找到类似函数sort.SearchStrings(slice, target)、sort.SearchFloat64s(slice, target)前提数组必须已排序在未排序数组上使用二分搜索结果不正确效率8个元素最多比较3次log₂83远优于线性搜索7. 搜索进阶 — 最值、计数、收集索引packagemainimportfmtfuncmain(){numbers:[10]int{64,34,25,12,22,11,90,88,76,50}// 求最小值和最大值同时min:numbers[0]max:numbers[0]minIndex:0maxIndex:0fori,value:rangenumbers{ifvaluemin{minvalue minIndexi}ifvaluemax{maxvalue maxIndexi}}fmt.Printf(Minimum: %d at index %d\n,min,minIndex)fmt.Printf(Maximum: %d at index %d\n,max,maxIndex)// 计数统计某值出现的次数countTarget:12count:0for_,value:rangenumbers{ifvaluecountTarget{count}}fmt.Printf(Number %d appears %d times\n,countTarget,count)// 收集所有匹配的索引searchValue:34varindices[]intfori,value:rangenumbers{ifvaluesearchValue{indicesappend(indices,i)}}fmt.Printf(Value %d found at indices: %v\n,searchValue,indices)}执行结果Minimum: 11 at index 5 Maximum: 90 at index 6 Number 12 appears 1 times Value 34 found at indices: [1]要点求最值从numbers[0]开始逐个比较更新 min/max 和对应的索引计数遍历所有元素匹配目标值时count收集索引var indices []int创建空切片append(indices, i)追加匹配的索引%v— 切片的默认格式输出[1]这些操作都是 O(n) 线性扫描无法用二分搜索优化除非需要的是排序后的位置实际场景数据分析、过滤、统计等知识点总结知识点关键概念多维数组[3][3]int— “数组的数组”len取行数和列数多维数组遍历嵌套 for/range外层遍历行内层遍历每行元素sort 包排序sort.Ints(slice)— 数组需用[:]转切片排序修改原数组逆序排序sort.Sort(sort.Reverse(sort.IntSlice(slice)))— 三层包装线性搜索逐个比较 O(n)适用于未排序数组二分搜索sort.SearchIntsO(log n)只适用于已排序数组需验证结果最值/计数/索引收集遍历统计append收集匹配索引