Go语言の排序和查找

  • 本文主要讲Go语言的以下知识点
    • 冒牌排序
    • 顺序查找
    • 二分法查找
    • 二维数组

排序的基本介绍

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

排序的分类:

  1. 内部排序:

    指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法,选择式排序法和插入式排序法);

  2. 外部排序法:

    数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法)。

冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素的排序码,若发现逆序则交换,使排序码较小的元素逐渐从后部移向前部(从下标较大的单元移向下标较小的单元),就像水底下的气泡一样逐渐向上冒。

因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较(优化)。

冒泡排序的思路分析

冒泡排序实现

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 {23,64,224,76,34}
	
	BubbleSort(&arr)
	fmt.Println("main arr=", arr) //有序的哦
}

课后练习

需要牢记冒泡排序的代码!能默写出来才行

查找

  • 介绍

    在Golang中,我们常用的查找有两种:

    1. 顺序查找
    2. 二分查找(数组有序)
  • 案例演示:

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

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

    代码:

package main

import (
	"fmt"
)
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 \n", heroName, i)
			break
		} else if i == (len(names) - 1) {
			fmt.Printf("没有找到%v \n", heroName)
		}
	}
	//顺序查找 第二种方式 (推荐)
	index := -1
	for i := 0; i < len(names); i++ {
		if heroName == names[i] {
			index = i //赋值
			break
		}
	}
	if index != -1 {
		fmt.Printf("找到%v, 下标为%v\n", heroName, index)
	} else {
		fmt.Println("没有找到",heroName)
	}
}
 ~/go/src/go_code/chapter08/demo02/main  go run ./main.go
请输入要查找的人名...
金毛狮王
找到金毛狮王,下标为1 
找到金毛狮王, 下标为1
  1. 请对一个有序数组进行二分查找 {1,8,10,89,1000,1234},输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示“没有这个数”。【使用到递归】
package main

import (
	"fmt"
	//"time"
	//"math/rand"
)
func BinaryFind(arr *[6]int,leftIndex int,rightIndex int,findVal int) {
	if leftIndex > rightIndex {
		fmt.Println("找不到哦找不到哦")
		return 
	}
	middle := (leftIndex + rightIndex) / 2
	if (*arr)[middle] > findVal {
		BinaryFind(arr, leftIndex, middle - 1, findVal) 
	} else if (*arr)[middle] < findVal {
		BinaryFind(arr, middle + 1, rightIndex, findVal)
	} else {
		fmt.Println("这个数字的下标位置在",middle)
	}
}
func main(){
	var arrs [6]int = [6]int {1,8,10,89,1000,1234}
	fmt.Println("请输入一个数:")
	var num int = 0
	fmt.Scanln(&num)
	BinaryFind(&arrs, 0, len(arrs), num)

}
 ~/go/src/go_code/chapter08/demo03/main  go run ./main.go
请输入一个数:
1001
找不到哦找不到哦
 ~/go/src/go_code/chapter08/demo03/main  go run ./main.go
请输入一个数:
1000
这个数字的下标位置在 4

二维数组的介绍

如你所见 就是二维数组罢了

二维数组应用场景

比如开发了一个五子棋游戏,棋盘就需要二维数组来表示。如图

二维数组快速入门

快速入门案例:

  • 请用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0
  • 代码演示
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.Printf("%v ",arr[i][j])
    }
    fmt.Println()
  }
}

使用方式1:先声明/定义,再赋值

  • 语法 var 数组名 [大小][大小]类型
  • 比如 var arr [2][3]int,再赋值
  • 使用演示
  • 二维数组在内存的存在形式(重点)

var arr2 [2][3]int // 以这个为例来分析arr2在内存的布局!!
arr2[1][1] = 10
fmt.Println(arr2)

fmt.Printf("arr2[0]的地址%p\n", &arr2[0])
fmt.Printf("arr2[1]的地址%p\n", &arr2[1])

fmt.Printf("arr2[0][0]的地址%p\n", &arr2[0][0])
fmt.Printf("arr2[1][0]的地址%p\n", &arr2[1][0])
 ~/go/src/go_code/chapter08/demo04/main  go run ./main.go
[[0 0 0] [0 10 0]]
arr2[0]的地址0xc0000ac030
arr2[1]的地址0xc0000ac048
arr2[0][0]的地址0xc0000ac030
arr2[1][0]的地址0xc0000ac048

使用方式2:直接初始化

  • 声明:var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值..},{初值..}}
  • 赋值(有默认值,比如int类型的就是0)
  • 使用演示
var arr3 [2][3]int = [2][3]int{{1,2,3},{4,5,6}}
fmt.Println("arr3=",arr3)
arr3= [[1 2 3] [4 5 6]]
  • 说明:二维数组在声明/定义时也对应有四种写法[和一维数组类似]
var 数组名 [大小][大小]类型 = [大小][大小]类型{{},{}}
var 数组名 [大小][大小]类型 = [...][大小]类型{{初值..},{初值..}}
var 数组名 = [大小][大小]类型{{初值..},{初值..}}
var 数组名 = [...][大小]类型{{初值..},{初值..}}

二维数组的遍历

  • 双层for循环完成遍历
  • for-range方式完成遍历

实例演示:

func main(){
  var arr3 = [2][3]int{{1,2,3},{4,5,6}}
  //for循环遍历
  for i := 0; i < len(arr3); i++ {
    for j := 0; j < len(arr3[i]); j++ {
      fmt.Printf("arr3[%v][%v] = %v\t", i, j, arr3[i][j])
    }
    fmt.Println()
  }
  fmt.Println()
  //for-range遍历二维数组
  for i, v1 := range arr3 {
    for j, v2 := range v1 {
      fmt.Printf("arr3[%v][%v] = %v \t", i, j, v2)
    }
    fmt.Println()
  }
}
 ~/go/src/go_code/chapter08/demo05/main  go run ./main.go
arr3[0][0] = 1  arr3[0][1] = 2  arr3[0][2] = 3
arr3[1][0] = 4  arr3[1][1] = 5  arr3[1][2] = 6

arr3[0][0] = 1  arr3[0][1] = 2  arr3[0][2] = 3 
arr3[1][0] = 4  arr3[1][1] = 5  arr3[1][2] = 6 

二维数组的应用案例

  • 要求如下:

    定义二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级平均分,以及所有班级平均分

  • 代码

func main(){
  var scores [3][5]float64
  fmt.Println("请按照提示输入成绩:")
  for i := 0; i < len(scores); i++ {
    for j := 0; j < len(scores[i]); j++ {
      fmt.Printf("请输入%v班的第%v个成绩:", i+1, j+1)
      fmt.Scanln(&scores[i][j])
    }
  }
  //计算各班平均分
  totalSum := 0.0
  count := 0
  for i := 0; i < len(scores); i++ {
    sum := 0.0
    for j := 0; j < len(scores[i]); j++ {
      sum += scores[i][j]
      count++
    }
    totalSum += sum
    fmt.Printf("第%d个班的总分为%v,平均分为%v \n", i+1, sum, sum / float64(len(scores[i])))
  }
  fmt.Printf("所有人总分为%v,平均分为%v\n",totalSum, totalSum / float64(count))
}
 ~/go/src/go_code/chapter08/demo06/main  go run ./main.go
请按照提示输入成绩:
请输入1班的第1个成绩:70
请输入1班的第2个成绩:80
请输入1班的第3个成绩:60.5
请输入1班的第4个成绩:99
请输入1班的第5个成绩:100
请输入2班的第1个成绩:78
请输入2班的第2个成绩:97
请输入2班的第3个成绩:87
请输入2班的第4个成绩:67
请输入2班的第5个成绩:66
请输入3班的第1个成绩:99
请输入3班的第2个成绩:56
请输入3班的第3个成绩:87
请输入3班的第4个成绩:75
请输入3班的第5个成绩:70.4
第1个班的总分为409.5,平均分为81.9 
第2个班的总分为395,平均分为79 
第3个班的总分为387.4,平均分为77.47999999999999 
所有人总分为1191.9,平均分为79.46000000000001