• 八、排序和查找


    8.1 排序的介绍

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

    8.2 排序的分类:

    1、内部排序

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

    2、外部排序法

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

    8.3 交换式排序

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

    交换式排序又可分为两种:

    ​ 1、冒泡排序法(Bubble sort)

    ​ 2、快速排序法(Quick sort)

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

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

    8.4 冒泡排序法案例

    24、69、80、57、13使用冒泡排序法将其排成一个从小到大的有序数列

    354464646.PNG

    8.5 冒泡排序代码实现

    354464646.PNG

    最终实现方法

    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} 输入一个数看看该数是否存在此数,并且求出下标,如果没有就提示“没有这个数”

    分析图

    tgHoJU.png

    代码

    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、使用演示 t2i4TU.png

    4、二维数组在内存的存在形式(重点)

    t2k8xA.png

    8.7.2 使用方式2:直接初始化

    1、声明:var 数组名[大小] [大小]类型 = [大小] [大小]类型{{初值...},{初值...}}

    2、赋值(有默认值,比如int 类型就是0)

    3、使用演示:

    t2AKLq.png

    4、说明:二维数组在声明/定义时也对应有四种写法[和一维数组类似]

    • var 数组名[大小] [大小]类型 = [大小] [大小]类型{{初值...},{初值...}}
    • var 数组名[大小] [大小]类型 = [...]类型{{初值...},{初值...}}
    • var 数组名 = [大小] [大小]类型{{初值...},{初值...}}
    • var 数组名 = [...] [大小]类型{{初值...},{初值...}}

    8.7.3 二维数组的遍历

    1、双层for循环完成遍历

    t2EzDI.png

    2、for-range方式完成遍历

    t2VLd0.png

    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)
    }
    

    结果为

    t2npQg.png

  • 相关阅读:
    火狐浏览器处理jquery中:header的问题。
    兼容IE与FF的childNodes问题(ff childNodes)
    前端开发的几个辅助类工具
    固定 vs. 流动 vs. 弹性:哪种布局更适合你?
    由浅入深漫谈margin属性
    Firefox 的 Jetpack 扩展案例分析:Gmail 邮件提醒
    jQuery性能优化
    浅谈.NET中可用的定时器和计时器【上篇】
    现有分布式技术(socket、.net remoting、asp.net webservice、WSE、ES)和wcf的比较及优势
    Mono for Android 4.2初探
  • 原文地址:https://www.cnblogs.com/jiaxiaozia/p/13059258.html
Copyright © 2020-2023  润新知