Golang学习笔记(05)

第八章 排序和查找

排序的基本介绍

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

排序的分类

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

交换式排序法

交换式排序属于内部排序法,是运用数据值比较后,依判断规则对数据位置进行交换,以达到排序目的。

  1. 冒泡排序法(Bubble sort):基本思想:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素排序码,若发现逆序则交换,是排序码较小的元素逐渐从后部移向前部(从下标较大的单元移向较小的单元)
    冒泡排序的规则:
    (1)一共会经过arr.length-1次的轮数的比较,每一轮确定一个数的比较
    (2)每一轮的比较次数在逐渐的减少
    (3)当发现前面的一个数比后面的一个数大的时候,就进行了交换
    在这里插入图片描述
package main

import (
	"fmt"
)

// BubbleSort 冒泡排序
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] { //从小到大排序 从大到小排序: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) //有序的
}

  1. 快速排序法(Quick sort)

查找

介绍

在Golang中,常用的查找方式有:

  1. 顺序查找
package main

import "fmt"

func main() {
	names := [4]string{"北京", "上海", "长春", "杭州"}
	var cityName = ""
	fmt.Println("请输入要查找的城市名称")
	fmt.Scanln(&cityName)
	//顺序查找:第一种方式
	for i := 0; i < len(names); i++ {
		if cityName == names[i] {
			fmt.Printf("找到%v ,下标是%v\n", cityName, i)
			break
		} else if i == (len(names) - 1) {
			fmt.Printf("没有找到%v\n", cityName)
		}
	}
	//顺序查找:第二种方式
	index := -1
	for i := 0; i < len(names); i++ {
		if cityName == names[i] {
			index = i //将找到的值对应的下标赋值给index
			break
		}
	}
	if index != -1 {
		fmt.Printf("找到%v ,下标是%v\n", cityName, index)
	} else {
		fmt.Println("没有找到", cityName)
	}
}

  1. 二分查找(该数组是有序的)
    二分查找的思路
  2. arr是一个有序数组,并且是从小到大排序
  3. 先知道中间的下标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的逻辑会递归查找
  4. 分析退出递归的条件
    if leftIndex>rightIndex{
    //找不到…
    return…
    }
package main

import "fmt"

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 {
		BinaryFind(arr, leftIndex, middle-1, findVal)

	} else if (*arr)[middle] < findVal {
		BinaryFind(arr, middle+1, rightIndex, findVal)
	} else {
		fmt.Printf("找到了,下标为%v\n", middle)
	}
}
func main() {

	arr := [6]int{1, 8, 10, 89, 1000, 1234}
	BinaryFind(&arr, 0, len(arr)-1, 1000)
}

二维数组

入门案例

package main

import "fmt"

/*
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.Print(arr[i][j], " ")
		}
		fmt.Println()
	}

}

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

  1. 语法:var 数组名 [大小][大小]类型
  2. 比如 var arr [2][3]int,再赋值
  3. 二维数组在内存中的存在形式
    在这里插入图片描述

使用方法2:直接初始化

  1. 声明:var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值…},{初值…}}
  2. 赋值(有默认值)
  3. 基本使用
var arr [2][3]int = [2][3]int{{1, 2, 3}, {4, 5, 6}}
	fmt.Println("arr=", arr)

  1. 说明:二维数组在声明/定义时也对应有四种写法
    var 数组名 [大小][大小]类型 = [大小][大小]类型{{初值…},{初值…}}
    var 数组名 [大小][大小]类型 = […][大小]类型{{初值…},{初值…}}
    var 数组名 = [大小][大小]类型{{初值…},{初值…}}
    var 数组名 = […][大小]类型{{初值…},{初值…}}

二维数组的遍历

  1. 双层for循环完成遍历
package main

import "fmt"

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

		}
		fmt.Println()
	}
}

  1. for-range方式完成遍历
//for-range遍历二维数组
	for i, v := range arr {
		for j, v2 := range v {
			fmt.Printf("arr[%v][%v]=%v\t", i, j, v2)
		}
		fmt.Println()
	}

数组和查找相关案例

  1. 随机生成十个整数(1-100的范围)保存到数组,并且倒序打印以及求平均值、求最大值和最大值下标、并查找里面是否有55
package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 随机生成十个整数(1-100的范围)保存到数组,
// 并且倒序打印以及求平均值、求最大值和最大值下标、并查找里面是否有55
// 倒序输出
func daoxu(arr [10]int) {
	temp := 0
	for i := 0; i < len(arr)/2; i++ {
		temp = arr[10-i-1]
		arr[10-i-1] = arr[i]
		arr[i] = temp
	}
	fmt.Println("倒序打印的数组为=", arr)
}

// 求平均值
func average(arr [10]int) {
	sum := 0.0
	for i := 0; i < len(arr); i++ {
		sum += float64(arr[i])
	}
	fmt.Println("平均值为=", sum/float64(len(arr)))
}

// 求最大值
func max(arr [10]int) {
	max := 0
	index := 0
	for i := 0; i < len(arr); i++ {
		if arr[i] > max {
			max = arr[i]
			index = i
		}
	}
	fmt.Printf("最大值是%d,最大值下标为%d\n", max, index)
}

// 判断数组中是否有55
func find(arr [10]int, findVal int) {
	var num = -1
	var index = 0
	for i := 0; i < len(arr); i++ {
		if arr[i] == findVal {
			num = arr[i]
			index = i
		}
	}
	if num != -1 {
		fmt.Printf("找到了,下标为%d", index)
	} else {
		fmt.Println("没有找到")
	}
}

func main() {
	var arr [10]int
	rand.NewSource(time.Now().UnixNano())
	for i := 0; i < 10; i++ {
		arr[i] = rand.Intn(101)
	}
	fmt.Println("生成的数组为:", arr)
	daoxu(arr)
	average(arr)
	max(arr)
	find(arr, 55)
}
  1. 已知有个排序好(升序)的数组,要求插入一个元素,最后打印该数组,顺序依然是升序。
package main

import "fmt"
// 任意位置插入数字类型的元素
// @param slice []int 将指定元素插入的切片
// @param num int 插入的指定元素
// @param index int 插入的指定位置
func arbitrarilyInsertElement(slice []int, num int, index int) []int {
	slice = append(slice[:index], append([]int{num}, slice[index:]...)...)
	return slice
}

// 2、已知有个排序(升序)的数组,要求插入一个元素,最后打印该数组,顺序依然是升序
func exec2(arr [5]int, leftIndex int, rightIndex int, num int) bool {
	slice := arr[:] // 将数组转成切片后才能新增元素
	// 因为数组是升序的,所以可以使用二分查找来做exec2
	middleIndex := (leftIndex + rightIndex) / 2 // 中间值的索引
	middle := slice[middleIndex]                // 中间值

	if leftIndex > rightIndex {
		// 防止右值索引小于0
		if rightIndex < 0 {
			rightIndex = 0
		}

		if num > arr[rightIndex] {
			// num在中间值右侧,左值索引向右移动(+1),右值索引不变,所以使用rightIndex
			// 因为左值索引向右移动了,所以当前左值索引(leftIndex)就是需要将num插入的位置
			slice = arbitrarilyInsertElement(slice, num, leftIndex)
		} else if num < arr[leftIndex] {
			// num在中间值左侧,右值索引向左移动(-1),左值索引不变,所以使用leftIndex
			// 因为右值索引向左移动了,所以当前右值索引(rightIndex)就是需要将num插入的位置
			slice = arbitrarilyInsertElement(slice, num, rightIndex)
		}
		fmt.Println("slice=", slice)
		return false
	}

	if num < middle {
		rightIndex = middleIndex - 1
	} else if num > middle {
		leftIndex = middleIndex + 1
	} else if num == middle {
		// num等于中间值,所以可以直接使用中间值索引(middleIndex)作为将num插入的位置
		slice = arbitrarilyInsertElement(slice, num, middleIndex)
		fmt.Println("slice=", slice)
		return true
	}
	return exec2(arr, leftIndex, rightIndex, num)
}

func main() {
	arr := [5]int{1, 3, 5, 7, 9} // 升序数组
	// 要插入的值
	num := 0
	fmt.Println("请输入插入的数字")
	fmt.Scanln(&num)
	exec2(arr, 0, len(arr)-1, num)
}
  1. 定义一个3行4列的二维数组,逐个从键盘输入值,编写程序将四角的数据清0
package main

import "fmt"

// 定义一个3行4列的二维数组,逐个从键盘输入值,编写程序将四周的数据清0

func clear(arr *[3][4]int) {
	for i := 0; i < len(arr); i++ {
		if i == 0 || i == len(arr)-1 {
			for j := 0; j < len(arr[i]); j++ {
				arr[i][j] = 0
			}
		} else {
			for j := 0; j < len(arr[i]); j++ {
				if j == 0 || j == len(arr[i])-1 {
					arr[i][j] = 0
				}
			}
		}

	}
}
func main() {
	var arr [3][4]int
	for i := 0; i < len(arr); i++ {
		for j := 0; j < len(arr[i]); j++ {
			fmt.Printf("请输入第%v行,第%v个元素的值:\n", i+1, j+1)
			fmt.Scanln(&arr[i][j])
		}
	}
	clear(&arr)
	for _, value := range arr {
		for _, value2 := range value {
			fmt.Print(value2, "")
		}
		fmt.Println()
	}
}

  1. 定义一个4行4列的二维数组,逐个从键盘输入值,让后价格第一行和第四行的数据进行交换,第二行和第三行的数据进行交换。
package main

import "fmt"

// 定义一个3行4列的二维数组,逐个从键盘输入值,编写程序将四周的数据清0

func main() {
	var multiArray = [4][4]int{}
	for i := 0; i < len(multiArray); i++ {
		for j := 0; j < len(multiArray[i]); j++ {
			fmt.Printf("请输入第%v行,第%v个元素:\n", i+1, j+1)
			fmt.Scanln(&multiArray[i][j])
		}
	}
	for i := 0; i < len(multiArray); i++ {
		for j := 0; j < len(multiArray[i]); j++ {
			fmt.Print(multiArray[i][j], " ")
		}
		fmt.Println()
	}
	fmt.Println()
	fmt.Println()

	swap1 := [len(multiArray[0])]int{}
	swap2 := [len(multiArray[1])]int{}
	swap1 = multiArray[0]
	multiArray[0] = multiArray[3]
	multiArray[3] = swap1

	swap2 = multiArray[1]
	multiArray[1] = multiArray[2]
	multiArray[2] = swap2
	for i := 0; i < len(multiArray); i++ {
		for j := 0; j < len(multiArray[i]); j++ {
			fmt.Print(multiArray[i][j], " ")
		}
		fmt.Println()

	}
}

  1. 试保存1 3 5 7 9 五个奇数到数组,并倒序打印
package main

import "fmt"

// 定义一个3行4列的二维数组,逐个从键盘输入值,编写程序将四周的数据清0

func main() {
	var arr = [5]int{}
	for i := 0; i < len(arr); i++ {
		fmt.Printf("请输入第%v个奇数\n", i+1)
		fmt.Scanln(&arr[i])
	}
	fmt.Println(arr)
	tempIndex := len(arr)
	tempArr := [5]int{}
	for i := 0; i < len(arr); i++ {
		tempIndex--
		tempArr[tempIndex] = arr[i]
	}
	arr = tempArr
	fmt.Println(arr)
}

  1. 试写出实现查找的核心代码,比如已知数组arr[10]string:里面保存了十个元素,先要查找“AA”在其中是否存在,打印提示,如果有多个“AA”,也要找到对一个的下标。
package main

import "fmt"

//试写出实现查找的核心代码,比如已知数组arr[10]string:
//里面保存了十个元素,先要查找“AA”在其中是否存在,
// 打印提示,如果有多个“AA”,也要找到对一个的下标。

func search(sliceArr []string, target string) (targetIndex []int) {
	count := 0
	for i := 0; i < len(sliceArr); i++ {
		if sliceArr[i] == target {
			targetIndex = append(targetIndex, i)
			count++
		}
	}
	if count == 0 {
		fmt.Printf("数组中没有'%s'\n", target)
	} else {
		fmt.Printf("'%s'在数组中有%d个\n", target, count)
	}
	return targetIndex
}
func main() {
	var arr = []string{"上海", "杭州", "北京", "深圳", "杭州"}
	var target string
	fmt.Println("请输入想要查找的城市:")
	fmt.Scanln(&target)
	fmt.Printf("该元素对应的下标为:%v\n", search(arr, target))
}

  1. 随机生成10个整数(1-100)之间,使用冒泡排序法进行排序,然后用二分查找发,查找是否有90这个数,并显示下标,如果没有则提示“找不到该数”。
package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 随机生成10个整数(1-100),使用冒泡排序进行排序,然后用二分查找法查找是否有90这个数,
// 并显示下标,如果没有则提示“找不到该数”。
func bubbleSort(arr []int) []int {
	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
			}

		}
	}
	return arr
}
func finary(arr []int, leftIndex int, rightIndex int, target int) {
	midIndex := (leftIndex + rightIndex) / 2
	if rightIndex < leftIndex {
		fmt.Println("找不到该数")
		return
	}
	if target > arr[midIndex] {
		finary(arr, midIndex+1, rightIndex, target)
	} else if target < arr[midIndex] {
		finary(arr, midIndex+1, rightIndex, target)
	} else if target < arr[midIndex] {
		finary(arr, leftIndex, midIndex-1, target)
	} else {
		fmt.Println("该数存在,下标为", midIndex)
	}
}
func main() {
	var arr = make([]int, 10)
	rand.NewSource(time.Now().UnixNano())
	for i := 0; i < 10; i++ {
		arr[i] = rand.Intn(101)
	}
	fmt.Println(arr)
	arr = bubbleSort(arr)
	fmt.Println(arr)
	finary(arr, 0, len(arr)-1, 90)
}

  1. 编写一个函数,可以接收一个数组,该数组有5个数,请找出最大的数和最小的数和对应的数组下标是多少.
package main

import "fmt"

// 编写一个函数,可以接收一个数组,该数组有5个数,
// 请找出最大的数和最小的数和对应的数组下标是多少
func findNum(arr *[5]int) (max int, maxIndex int, min int, minIndex int) {
	max = (*arr)[0]
	min = (*arr)[0]
	for i := 0; i < len(arr); i++ {
		if (*arr)[i] > max {
			max = (*arr)[i]
			maxIndex = i
		}
	}
	for i := 0; i < len(arr); i++ {
		if (*arr)[i] < min {
			min = (*arr)[i]
			minIndex = i
		}
	}
	return max, maxIndex, min, minIndex
}
func main() {
	var arr [5]int = [5]int{12, 34, 45, 23, 17}
	max, maxIndex, min, minIndex := findNum(&arr)
	fmt.Printf("max = %v  ,maxIndex = %v  ,min = %v  ,minIndex = %v  ", max, maxIndex, min, minIndex)

}

  1. 定义一个数组,并给出8个整数,求该数组中大于平均值的数的个数,和小于平均值的数的个数
package main

import "fmt"

// 定义一个数组,并给出8个整数,求该数组中大于平均值的数的个数,和小于平均值的数的个数
func function(arr *[8]int) (num1 int, num2 int) {
	var sum float64
	for i := 0; i < len(*arr); i++ {
		sum += float64((*arr)[i])
	}
	average := sum / float64(len(*arr))
	for i := 0; i < len(*arr); i++ {
		if float64((*arr)[i]) > average {
			num1++
		} else {
			num2++
		}
	}
	return num1, num2
}

func main() {
	arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
	num1, num2 := function(&arr)
	fmt.Printf("大于平均数的个数是%v,小于平均数的个数是%v", num1, num2)
}

  1. 跳水比赛:8个评委打分。运动员的成绩是8个成绩去掉一个最高分,去掉一个最低分,剩下的六个分数的平均分就是最后得分。使用一维数组实现如下功能:
    (1)请把打最高分的评委和最低分的评委找出来
    (2)找出最佳评委和最差评委。最佳评委就是打分和最后得分最近的评委。最差评委就是打分和最后得分相差最大的
package main

import "fmt"

/*
跳水比赛,8个评委打分,运动员的成绩是8个成绩中去掉一个最高分,去掉一个最低分,
剩下6个成绩的平均分就是最终得分。使用一维数组实现以下功能:
1.把打最高分的评委和打最低分的评委找出来
2.找出最佳评委和最差评委。
最佳评委就是打分和最终成绩最接近的评委,最差评委就是打分和最终成绩相差最大的评委
*/
//冒泡排序
func scoreBubble(score []float32) (bubble []float32) {
	var temp float32
	for k := 0; k < len(score)-1; k++ {
		for i := 0; i < len(score)-1-k; i++ {
			if score[i] > score[i+1] {
				temp = score[i]
				score[i] = score[i+1]
				score[i+1] = temp
			}
		}
	}
	return score
}

// 求最终成绩的函数
func finalScore(bubbleScore []float32) float32 {
	finalScoreList := bubbleScore[1 : len(bubbleScore)-1]
	var sum float32
	for i := 0; i < len(finalScoreList); i++ {
		sum += finalScoreList[i]
	}
	return sum / float32(len(finalScoreList))
}

// 求出最差评委所打分数的函数
// 最差评委:用最终得分和最高成绩(即数组最末尾的元素)及最低成绩(即数组第一个元素)相减
// 如果最低成绩和最终成绩的差大于最高成绩和最终成绩的差,那么最差评委就是打最低成绩的那个评委
func worstJudge(finalScore float32, bubbleScore []float32) float32 {
	if (finalScore - bubbleScore[0]) > (bubbleScore[len(bubbleScore)-1] - finalScore) {
		return bubbleScore[0]
	} else {
		return bubbleScore[len(bubbleScore)-1]
	}
}

// 求出最佳评委所打分数的函数
// 最佳评委:用最终成绩和每一个评委打出的成绩求差,差最小的为最佳评委
// 用最终成绩左右两边最接近的成绩分别与最终成绩求差,差最小的为最佳评委
func bestJudge(finalScore float32, bubbleScore []float32) float32 {
	var finalLeft float32
	var finalRight float32
	for i := 0; i < len(bubbleScore); i++ {
		if finalScore > bubbleScore[i] {
			finalLeft = bubbleScore[i]
			finalRight = bubbleScore[i+1]
		}
	}
	if (finalScore - finalLeft) < (finalRight - finalScore) {
		return finalLeft
	} else {
		return finalLeft
	}
}
func main() {
	var rowScore = [8]float32{5, 6.5, 9, 5, 9.5, 7, 5.5, 9.5} //将原始成绩单独保存

	//新建一个数组用来存放原始成绩,目的是防止排序操作后原始成绩也跟着排序,
	//如果原始成绩也跟着排序,那么就无法比对出最佳和最差成绩所在的位置了
	var score = [8]float32{}
	score = rowScore //将原始成绩赋给新建数组

	bubbleScore := score[:]                //对其切片处理,目的是传入函数
	bubbleScore = scoreBubble(bubbleScore) //调用将成绩排序的函数,并接收返回值

	finalScore := finalScore(bubbleScore) //调用求最终成绩的函数,并接收返回值
	fmt.Printf("最终成绩为:%.1f\n", finalScore)

	worstJudge := worstJudge(finalScore, bubbleScore) //调用求最差成绩的函数,并接收返回值

	bestJudge := bestJudge(finalScore, bubbleScore) //调用求最佳成绩的函数,并接收返回值

	//最后将最差成绩和最佳成绩放到原始成绩里比对,找出其所在位置
	fmt.Println("原始成绩:", rowScore)
	for i := 0; i < len(rowScore); i++ {
		if rowScore[i] == worstJudge {
			fmt.Printf("最差评委是打%.1f分的评委,该分数被第%d个评委打出\n", worstJudge, i)
		}
	}

	for i := 0; i < len(rowScore); i++ {
		if rowScore[i] == bestJudge {
			fmt.Printf("最佳评委是打%.1f分的评委,该分数被第%d个评委打出\n", bestJudge, i)
		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值