8.1 排序的介绍
排序是将一群数据,依指定的顺序进行排列的过程
8.2 排序的分类:
1、内部排序
指将需要处理的所有数据都加载到内部存储器中进行排序,包括(交换式排序法,选择式排序法和插入式排序法)
2、外部排序法
数据量过大,无法全部加载到内存中,需要借助外部存储进行排序,包括(合并排序法和直接合并排序法)
8.3 交换式排序
交换式排序属于内部排序法,是运用数值比较后,依判断规则对数据位置进行交换,以达到排序的目的
交换式排序又可分为两种:
1、冒泡排序法(Bubble sort)
2、快速排序法(Quick sort)
冒泡排序的基本思想是:通过对待排序序列从后向前(从下标比较大的元素开始),一次比较相邻元素的序码,若发现逆序则交换,使排序码较小的元素逐渐从后部移向前部(从下标比较大的单元移向下标较小的单元),就像水底下的气泡一样逐渐向上冒
因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明排序有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较(优化)。
8.4 冒泡排序法案例
24、69、80、57、13使用冒泡排序法将其排成一个从小到大的有序数列
8.5 冒泡排序代码实现
最终实现方法
package main
import (
"fmt"
)
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 := [5]int{24,69,80,57,13}
// 将数组传递给一个函数,完成排序
BubbleSort(&arr)
fmt.Println("main arr=", arr)
}
第一次冒泡排序代码
package main
import (
"fmt"
)
func BubbleSort(arr *[5]int) {
fmt.Println("排序前arr=", (*arr))
temp := 0 //临时变量(用于做交换)
// 冒泡排序:一步一步推导出来的
for j := 0; j < 4; 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 := [5]int{24,69,80,57,13}
// 将数组传递给一个函数,完成排序
BubbleSort(&arr)
// fmt.Println("main arr=", arr)
}
第二次冒泡排序
package main
import (
"fmt"
)
func BubbleSort(arr *[5]int) {
fmt.Println("排序前arr=", (*arr))
temp := 0 //临时变量(用于做交换)
// 冒泡排序:一步一步推导出来的
for j := 0; j < 4; j++ {
if (*arr)[j] > (*arr)[j + 1] {
// 以下三行 代码是进行交换
temp = (*arr)[j]
(*arr)[j] = (*arr)[j + 1]
(*arr)[j + 1] = temp
}
}
fmt.Println("第一次排序后arr=", (*arr))
for j := 0; j < 3; 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 := [5]int{24,69,80,57,13}
// 将数组传递给一个函数,完成排序
BubbleSort(&arr)
// fmt.Println("main arr=", arr)
}
8.6 查找
介绍
在Golang中,我们常用的查找有两种:
- 顺序查找
- 二分查找 (数组是有序的)
案例演示
- 有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王,从键盘输入一个名称,判断数列中是否包含此名称
package main
import (
"fmt"
)
func main() {
// 思路
// 1、定义一个数组
// 2、从控制台接收一个名词,依次比较,如果发现有,提示
names := [4]string{"白眉鹰王","金毛狮王","紫衫龙王","青翼蝠王"}
var heroName = ""
fmt.Println("请输入要查找的人名:")
fmt.Scanln(&heroName)
// 顺序查找第一种方式
for i := 0; i < len(names); i++ {
if heroName == names[i] {
fmt.Printf("1-找到了%v,下标为%v
", heroName, i)
break
} else if i == len(names) - 1 {
fmt.Printf("1-没有找到%v
", heroName)
}
}
// 顺序查找第2种方式
index := -1
for i := 0; i < len(names); i++ {
if heroName == names[i] {
index = i //将找到的值对应的下标赋给 index
break
}
}
if index != -1 {
fmt.Printf("2-找到了%v,下标为%v
", heroName, index)
} else {
fmt.Println("2-没有找到", heroName)
}
}
- 请求一个有序数组进行二分查找{1.8, 10, 89, 1000,1234} 输入一个数看看该数是否存在此数,并且求出下标,如果没有就提示“没有这个数”
分析图
代码
package main
import (
"fmt"
)
/*
二分查找的思路: 比如我们要查找的数是 findVal
1. arr是一个有序数组,并且是从小到大排序
2. 先找到 中间的下标 middle = (leftIndex + rightIndex) / 2, 然后让 中间下标的值和findVal进行比较
2.1 如果 arr[middle] > findVal , 就应该向 leftIndex ---- (middle - 1)
2.2 如果 arr[middle] < findVal , 就应该向 middel+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 --- middel-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, 10, 89, 1000, 1234}
BinaryFind(&arr, 0, len(arr) - 1, 1000)
// &arr是地址,因为上面的BiinaryFind接收的是一个指针
// 0, len(arr) - 1 表示是从下标为0 到这个数组的数组长度-1(即就是最后一个元素)
// 1 表示要具体查找的元素值 这里是1000
}
8.7 二维数组
8.7.1 使用方式1:先声明/定义再赋值
1、语法:var 数组名[大小] [大小] 类型
2、比如:var arr[2] [3]int[] [] 再赋值
3、使用演示
4、二维数组在内存的存在形式(重点)
8.7.2 使用方式2:直接初始化
1、声明:var 数组名[大小] [大小]类型 = [大小] [大小]类型{{初值...},{初值...}}
2、赋值(有默认值,比如int 类型就是0)
3、使用演示:
4、说明:二维数组在声明/定义时也对应有四种写法[和一维数组类似]
- var 数组名[大小] [大小]类型 = [大小] [大小]类型{{初值...},{初值...}}
- var 数组名[大小] [大小]类型 = [...]类型{{初值...},{初值...}}
- var 数组名 = [大小] [大小]类型{{初值...},{初值...}}
- var 数组名 = [...] [大小]类型{{初值...},{初值...}}
8.7.3 二维数组的遍历
1、双层for循环完成遍历
2、for-range方式完成遍历
8.7.4 二维数组的应用案例
定义二维数组,用于保存三个班,每个班5名同学成绩,并求出每个班级平均分,以及所有班级平均分
package main
import (
"fmt"
)
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)
}
结果为