5.2 Go 数组进阶学习笔记(多维、排序、搜索)
1. 多维数组 — 声明与访问
多维数组是"数组的数组",Go 通过[行][列]语法定义:
packagemainimport"fmt"funcmain(){// 声明 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;i<len(matrix);i++{forj:=0;j<len(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、5)- Go 没有专门的矩阵类型,多维数组就是"数组的数组"
2. 多维数组 — range 遍历与统计
用嵌套 range 遍历多维数组更简洁:
packagemainimport"fmt"funcmain(){grades:=[2][4]int{{85,92,78,96},{88,91,84,87}}// range 遍历:外层遍历行,内层遍历每行的元素fmt.Println("Grades:")fori,row:=rangegrades{fmt.Printf("Student %d: ",i+1)for_,grade:=rangerow{fmt.Printf("%d ",grade)}fmt.Println()}// 求所有元素总和:嵌套 for 循环vartotalSumintfori:=0;i<len(grades);i++{forj:=0;j<len(grades[i]);j++{totalSum+=grades[i][j]}}fmt.Println("Total sum of grades:",totalSum)// 获取维度:行数 × 列数rows:=len(grades)varcolsintifrows>0{cols=len(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]int),i是行号for _, grade := range row— 遍历每行的每个成绩- 求和:嵌套 for 遍历所有元素,
grades[i][j]用双重索引访问 - 维度:
len(grades)= 行数 = 2,len(grades[0])= 列数 = 4 - 注意:
grades的类型是[2][4]int,所以所有行的列数固定为4(数组长度是类型的一部分)
3. 数组排序 — sort 包
Go 的sort包提供排序函数,但只能对切片排序,需要用[:]把数组转为切片:
packagemainimport("fmt""sort")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.Reverse
sort.Sort(sort.Reverse(sort.IntSlice(slice)))实现降序排序:
packagemainimport("fmt""sort")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):
packagemainimport"fmt"funcmain(){numbers:=[10]int{64,34,25,12,22,11,90,88,76,50}target:=22foundIndex:=-1// -1 表示未找到fori,value:=rangenumbers{ifvalue==target{foundIndex=ibreak// 找到后立即退出}}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("fmt""sort")funcmain(){sortedNumbers:=[8]int{5,12,23,34,45,67,78,89}binaryTarget:=45// sort.SearchInts 在已排序切片中查找目标binaryIndex:=sort.SearchInts(sortedNumbers[:],binaryTarget)// 必须验证:SearchInts 返回的可能是"应插入的位置",而非找到的位置ifbinaryIndex<len(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₂8=3),远优于线性搜索
7. 搜索进阶 — 最值、计数、收集索引
packagemainimport"fmt"funcmain(){numbers:=[10]int{64,34,25,12,22,11,90,88,76,50}// 求最小值和最大值(同时)min:=numbers[0]max:=numbers[0]minIndex:=0maxIndex:=0fori,value:=rangenumbers{ifvalue<min{min=value minIndex=i}ifvalue>max{max=value maxIndex=i}}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{ifvalue==countTarget{count++}}fmt.Printf("Number %d appears %d times\n",countTarget,count)// 收集所有匹配的索引searchValue:=34varindices[]intfori,value:=rangenumbers{ifvalue==searchValue{indices=append(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收集匹配索引 |