Go-day04
今日概要:
1.内置函数、递归函数、闭包
2.数组与切片
3.map数据结构
4.package介绍
5.互斥锁和读写锁
一、内置函数
1.close:主要用来关闭channel
2.len:用来求长度,比如string、array、slice、map、channel
3.new:用来分配内存,主要用来分配值类型,比如int,struct返回的是指针
4.make:用来分配内存,主要用来分配引用类型,比如chan,map,slice
5.append:用来追加元素到数组、slice
6.panic和recover:用来做错误处理
new的例子:
package main import "fmt" func main() {
var i int
fmt.Println(i) j := new(int) //值类型分配内存地址
fmt.Println(j) //打印的是内存地址
*j = 100
fmt.Println(*j) //打印指针对应的值
} /*
0
0xc420014060
100
*/
new和make的区别:
package main import "fmt" func mytest(){ a := new([]int) //创建一个容量为0的切片,a为内存地址,当前为nil不能放值 b := make([]int,10) fmt.Println(a)
fmt.Println(b) //将切片插入值,a为内存地址只能操作指针
*a = make([]int,5) //通过make初始化容量为5
(*a)[0] = 100 //panic: runtime error: index out of range 因为空切片需要初始化
b[0] = 100
fmt.Println(a)
fmt.Println(b)
} func main() {
mytest()
}
/*
&[]
[0 0 0 0 0 0 0 0 0 0]
&[100 0 0 0 0]
[100 0 0 0 0 0 0 0 0 0]
*/
内置变量append
数组里append数组可以用数组...添加
目前有用到...的有 函数的可变长参数...,append加数组... 数组设置不想设置容量的时候 var a [...]int
package main import "fmt" func main() {
var a []int
a = append(a,20,3,40)
a = append(a,a...) //数组和数组相加可以用数组...
fmt.Println(a) }
内置变量panic和recover
recover是捕获异常,可以让服务不停止,比如一些异常想报警,但是又保证服务正常运行可以用defer+recover
package main import (
"time"
_ "fmt"
"errors"
) func getConfig() (err error){
return errors.New("init config failed!") //创建异常
} func test(){
/*
//通过recover捕获异常程序不退出
defer func(){
if err := recover(); err != nil{
fmt.Println(err)
}
}() b := 0
a := 100 / b //异常
fmt.Println(a)
*/
err := getConfig()
if err != nil{
panic(err) //通过panic抛出异常与python中的raise一样
}
return } func main() {
for {
test()
time.Sleep(time.Second * 1)
} }
二、递归函数
go里面的递归函数和python的很像,python支持递归1000层,go支持的远远大于python
设计原则
1.一个大问题能够分解成相似的小问题
2.定义好出口条件
通过递归求阶乘
package main import "fmt" //通过递归求阶乘
func calc(n int) int{
if n == 1{
return 1
}
return calc(n-1) *n
} func main() {
m := calc(5)
fmt.Println(m)
} /*
120
*/
通过递归求斐波那契
package main import "fmt" func fab(n int) int{
if n <= 1{
return 1
}
return fab(n-1) + fab(n-2) } func main() {
for i :=0 ; i < 10 ; i++ {
fmt.Println(fab(i))
} }
/*
1
1
2
3
5
8
13
21
34
55
*/
三、闭包
一个函数和与其相关的引用环境组合而成的实体,相当于闭包里面的变量,所有闭包都能读取
闭包例子一:
package main import "fmt" //返回值是一个func函数
func Adder() func (int) int { //类似一个类,x为类变量,修改都生效
var x int
return func(d int) int{//定义了一个匿名函数
x += d
return x
}
} func main() {
f := Adder()
fmt.Println(f(1))
fmt.Println(f(20))
fmt.Println(f(100)) } /*
1
21
121
*/
闭包例子二:
定义的时候传入了参数,类似于python里的实例化
package main import (
"strings"
"fmt"
) type str func(string) string func makeSuffix(suffix string) str { //make的时候传入suffix return func(name string) string{
if strings.HasSuffix(name,suffix) == false{
return name + suffix
}
return name
} } func main() {
f1 := makeSuffix(".mp3") fmt.Println(f1("bgm")) f2 := makeSuffix(".mp4") fmt.Println(f2("av")) } /*
bgm.mp3
av.mp4
*/
四、数组与切片
数组:
1.数组:是同一种数据类型的固定长度的序列。
2.数组定义:var a [len]int,比如:var a [5]int 一旦定义,长度不能改变
3.长度是数组类型的一部分,因此,var a [5] int和var a [10]int是不同的类型
4.数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
5.访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
6.数组是值类型,因此改变副本的值,不会改变本身的值
定义6的验证:
package main import "fmt" func test2(){ var a [10]int //数组是值变量,赋值之后新的改变,老的不会改变
b := a
b[0] = 100
fmt.Println(a) //[0 0 0 0 0]
} func main() {
test1() } /*
[0 0 0 0 0]
*/
变成指针修改当前数据原数据也被修改
package main import "fmt" func test3(a *[5]int){ //变成指针就成为引用类型
(*a)[0] = 10
} func main() { var a [5]int
test3(&a)
fmt.Println(a) } /*
[10 0 0 0 0]
*/
练习:
使用非递归的方式实现斐波那契数列,打印前100个数
package main import "fmt" func fab1(n int){
var sli []int64 //声明了一个切片
sli = make([]int64,n)//将切片设定容量
sli[0] = 1
sli[1] = 1
for i :=2 ; i < len(sli);i++{
sli[i] = sli[i-1] + sli[i-2]
} for _,value := range sli{ //通过for,range遍历切片
fmt.Println(value)
}
} func main() {
fab1(10)
}
/*
1
1
2
3
5
8
13
21
34
55
*/
循环数组的两种方式:
package main import "fmt" func test1(){
var a [5]int //定义一个数组 fmt.Println(a) //循环数组两种方式
//方式一
for i := 0; i < len(a) ; i++{
fmt.Println(a[i])
}
//方式二
for key,value := range a{
fmt.Printf("%d=[%d]\n",key,value)
} } func main() {
test1()
}
数组的初始化:
a. var age0 [5]int = [5]int{1,2,3}
b. var age1 = [5]int{1,2,3,4,5}
c. var age2 = […]int{1,2,3,4,5,6} 编译的时候自动求出来长度
d. var str = [5]string{3:”hello world”, 4:”tom”}
多维数组和多维数组遍历
a. var age [5][3]int
b. var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}} 定义了一个二维数组
例子:
package main import "fmt" //数组的初始化
func testArray(){
var a [5]int = [5]int{1,2,3,4,5}
var a1 = [5]int{2,3,4,5,6}
var a2 = [...]int{1,2,3}
var a3 = [...]string{1:"hello",3:"world"}
fmt.Println(a)
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
} //多维数组 func testArray1() {
var a = [2][5]int{{1,2,3,4,5},{6,7,8,9,0}} //第一个是有几个{},第二个是每个{}有几个元素
fmt.Println(a)
var b = [...][5]int{{1,2,3,4,5},{6,7,8,9,0}} //一维可以加...,其他不行
fmt.Println(b) //多维数组遍历
for row,v := range a{
for col,v1 := range v{
fmt.Printf("row:%d,col:%d,val:%d\t",row,col,v1)
}
fmt.Println()
}
} func main() {
testArray()
testArray1()
} /*
[1 2 3 4 5]
[2 3 4 5 6]
[1 2 3]
[ hello world]
*/
切片:
1. 切片:切片是数组的一个引用,因此切片是引用类型
2. 切片的长度可以改变,因此,切片是一个可变的数组
3. 切片遍历方式和数组一样,可以用len()求长度
4.cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组
5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int
6. 切片初始化:var slice []int = arr[start:end] 包含start到end之间的元素,但不包含end
7. var slice []int = arr[0:end]可以简写为 var slice []int=arr[:end]
8. var slice []int = arr[start:len(arr)] 可以简写为 var slice[]int = arr[start:]
9. var slice []int = arr[0, len(arr)] 可以简写为 var slice[]int = arr[:]
10. 如果要切片最后一个元素去掉,可以这么写: slice = slice[:len(slice)-1]
关于容量详解:
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
Slice_a := Array_a[2:5]
上面的代码真实存储方式,cap的容量是截取空间到最后的大小
练习:
package main import "fmt" func testSlice1() {
//切片是引用类型,传入函数中会改变原有值
var slice []int
var arr [5]int = [5]int{1, 2, 3, 4, 5} slice = arr[:]
slice = slice[1:]
slice = slice[:len(slice)-1] //刨除最后一个
fmt.Println(slice)
fmt.Println(len(slice))
fmt.Println(cap(slice)) slice = slice[0:1] //切片可以在切片,这样cap容量不变,len会变小
fmt.Println(len(slice))
fmt.Println(cap(slice))
} func main() { testSlice1()
} /*
[2 3 4]
3
4
1
4
*/
切片的内存布局:
切片本质上最底层还是数组,切片只是指针指向切片第一个值的内存地址,如果切片append的容量大于数组容量,底层会重新创建一个数组cap的值是成倍增长的
append
函数会改变slice
所引用的数组的内容,从而影响到引用同一数组的其它slice
。 但当slice
中没有剩余空间(即(cap-len) == 0
)时,此时将动态分配新的数组空间。返回的slice
数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice
则不受影响。
验证切片的内存地址和原数组切片第一个值的内存地址一致:
package main import "fmt" func testArray2(){
var a = [10]int{1,2,3,4} b := a[1:3]
fmt.Printf("%p\n",b) //验证b切片和数组内存地址一样,证明切片就是指针 fmt.Printf("%p\n",&a[1])//因为从第一个元素切的所以指针指向第一个内存地址 } func main() {
testArray2()
} /*
0xc42001a0f8
0xc42001a0f8
*/
通过自定义切片slice模拟切片操作
package main import "fmt" type slice struct { //封装成一个结构体
ptr *[100]int
len int
cap int
} func make1(s slice,cap int) slice{
s.ptr = new([100]int)
s.cap = cap
s.len = 0
return s
} func modify(s slice){
s.ptr[1] = 1000
} func testSlice(){
var s1 slice
s1 = make1(s1,10)
s1.ptr[0] = 100 modify(s1) fmt.Println(s1.ptr) } func main() { testSlice() }
/*
&[100 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
*/
通过make来创建切片
var slice []type = make([]type, len)
slice := make([]type, len)
slice := make([]type, len, cap)
底层实现(生成了一个cap为5的数组,将切片的指针指向数组的第一个值):
用append内置函数操作切片:
slice = append(slice, 10)
var a = []int{1,2,3}
var b = []int{4,5,6}
a = append(a, b…) 切片插入切片的时候用切片名加...
练习:
package main import "fmt" func testArray3(){
var arr [5]int = [...]int{1,2,3,4,5} s := arr[1:3]
fmt.Printf("before:len[%d],cap[%d]\n",len(s),cap(s)) s[1] = 100
fmt.Printf("arr=%p,slice=%p\n",&arr[1],s)
fmt.Println("before append",arr)
s = append(s,10)
s = append(s,10) s = append(s,10)
fmt.Printf("after:len[%d],cap[%d]\n",len(s),cap(s)) //容量翻倍增加
s = append(s,10)
s = append(s,10) s[1] = 1000
fmt.Println(s)
fmt.Println("after append",arr) //a的值还会变,只不过没超出之前改的还是原来的内存地址
fmt.Printf("arr=%p,slice=%p\n",&arr[1],s) //切片是可变长的,底层会创建一个新的数组,将指针指向新的数组 } func main() {
testArray3()
} /*
before:len[2],cap[4]
arr=0xc42001c098,slice=0xc42001c098
before append [1 2 100 4 5]
after:len[5],cap[8]
[2 1000 10 10 10 10 10]
after append [1 2 100 10 10]
arr=0xc42001c098,slice=0xc420018080
*/
for range切片遍历:
for index, val := range slice {
}
切片resize
var a = []int {1,3,4,5}
b := a[1:2]
b = b[0:3]
切片copy
package main import "fmt" func testCopy(){ var a []int = []int{1,2,3,4,5} b := make([]int,10) //[0,0,0,0,0,0,0,0,0,0] copy(b,a) //内置方法copy fmt.Println(b)
} func main() {
testCopy() } /*
[1 2 3 4 5 0 0 0 0 0]
*/
string和slice
string底层就是一个byte的数组,因此,也可以进行切片操作
string的底层布局
如何改变string中的字符值?
string本身是不可变的,因此要改变string中字符,需要如下操作:
package main import "fmt" func testModifyString(){
var a string = "我hello world"
b := []rune(a) //有中文的时候需要通过字符数组更改,强制转为数组
b[0] = '1'
fmt.Println(string(b)) }
func main() {
testModifyString()
}
slice的排序和查找操作:
排序操作主要都在 sort包中,导入就可以使用了
sort.Ints对整数进行排序, sort.Strings对字符串进行排序, sort.Float64s对浮点数进行排序.
sort.SearchInts(a []int, b int) 从数组a中查找b,前提是a必须有序
sort.SearchFloats(a []float64, b float64) 从数组a中查找b,前提是a必须有序
sort.SearchStrings(a []string, b string) 从数组a中查找b,前提是a必须有序
练习:
package main import (
"sort"
"fmt"
) func testIntSort(){
var a = [...]int{22,33,1,3,4} //数组是不能排序的,因为他是值类型 sort.Ints(a[:]) //将传入的值变为切片
fmt.Println(a) } func testStringSort(){
var a = [...]string{"aa","ccc","bbb","ffff"} sort.Strings(a[:])
fmt.Println(a) }
func testFloatSort(){
var a = [...]float64{0.38,0.02,0.01,0.44} sort.Float64s(a[:])
fmt.Println(a) } func testIntSearch(){
var a = [...]int{22,33,1,3,4} sort.Ints(a[:])
index := sort.SearchInts(a[:],22) //即便你不排序,默认也会排序,但是值会混乱
fmt.Println(index)
} func main() {
testIntSort()
testStringSort()
testFloatSort()
testIntSearch() } /*
[1 3 4 22 33]
[aa bbb ccc ffff]
[0.01 0.02 0.38 0.44]
3 */
注:从Go1.2开始slice支持了三个参数的slice,之前我们一直采用这种方式在slice或者array基础上来获取一个slice
var array [10]int
slice := array[2:4] 这个例子里面slice的容量是8,新版本里面可以指定这个容量
slice = array[2:4:7] 第三位是容量
上面这个的容量就是7-2
,即5。这样这个产生的新的slice就没办法访问最后的三个元素。
如果slice是这样的形式array[:i:j]
,即第一个参数为空,默认值就是0。
五、map(类似python的dict)
key-value的数据结构,又叫字典或关联数组
a.声明
声明是不会分配内存的,初始化需要make
var map1 map[keytype]valuetype
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string
b.map的相关操作
var a map[string]string = map[string]string{“hello”: “world”} 声明加赋值
a = make(map[string]string, 10) 初始化map
a[“hello”] = “world” 插入
val, ok := a[“hello”] 查找2个返回值,第一个是值,第二个为是否查到
for k, v := range a { 遍历map
fmt.Println(k,v)
}
delete(a, “hello”) 删除map中的key
len(a) 求map长度
例子:声明初始化和make初始化
package main import "fmt" func testMap(){
//声明初始化
var a map[string]string = map[string]string{
"asdas":"asdsdasd",
}
//make初始化
//a := make(map[string]string,10) a["abc"] = "cde" fmt.Println(a) }
func main() {
testMap() }
map是引用类型:
func modify(a map[string]int) {
a[“one”] = 134 //原来的map也会改变
}
slice里面放map
items := make([]map[int][int], 5) for I := 0; I < 5; i++ { items[i] = make(map[int][int]) }
练习:
package main import "fmt" func testMap(){
//声明初始化
var a map[string]string = map[string]string{
"asdas":"asdsdasd",
}
//make初始化
//a := make(map[string]string,10) a["abc"] = "cde" fmt.Println(a) } //多维数组
func testMap2(){
//因为有2层数组,需要初始化两次,才能使用,map,chan,slice都需要初始化,声明为nil
a := make(map[string]map[string]string,100)
a["key1"] = make(map[string]string,10)
a["key1"]["key2"] = "val1"
a["key1"]["key3"] = "val2"
a["key1"]["key4"] = "val3"
a["key1"]["key5"] = "val4" fmt.Println(a) } func modify2 (a map[string]map[string]string){ //查找
_, ok := a["zhangsan"] //固定写法,第一个为值,第二个为bool
if !ok {
a["zhangsan"] = make(map[string]string) //判断zhangsan是否存在,不存在就创建zhangsan与对应都map
} /* 等价写法
if a["zhangsan"] == nil{
a["zhangsan"] = make(map[string]string)
}
*/
a["zhangsan"]["nickname"] = "pangpang"
a["zhangsan"]["age"] = "18" return } //多维数组做用户信息保存
func testMap3(){
a := make(map[string]map[string]string,100)
modify2(a)
fmt.Println(a)
} func trans(a map[string]map[string]string){
//遍历map
for k,v := range a{
fmt.Println(k)
for k1,v1 := range v{
fmt.Println("\t",k1,v1)
}
}
} //多维数组一些操作
func testMap4(){
//遍历map
a := make(map[string]map[string]string,100)
a["key1"] = make(map[string]string,10)
a["key1"]["key2"] = "val1"
a["key1"]["key3"] = "val2"
a["key1"]["key4"] = "val3"
a["key1"]["key5"] = "val4" a["key2"] = make(map[string]string,10)
a["key2"]["key2"] = "val1"
a["key2"]["key3"] = "val2"
trans(a)
//删除map中key,map要全部清空for循环,或者重新make下
delete(a,"key1")
trans(a)
//求长度
fmt.Println(len(a)) } func testMap5(){
var a []map[int]int
a = make([]map[int]int,5) if a[0] == nil{ //默认只声明的map,或者slice都是nil
a[0] = make(map[int]int)
} a[0][10] = 100
fmt.Println(a)
} func main() {
//testMap()
//testMap2()
//testMap3()
//testMap4()
testMap5()
}
map的排序
a. 先获取所有key,把key进行排序
b. 按照排序好的key,进行遍历
package main import (
"fmt"
"sort"
) func testMapSort(){
//保证排序正常
var a map[int]int
a = make(map[int]int,5) a[0] = 1
a[2] = 3
a[3] = 4
a[10] =100 fmt.Println(a) var keys []int
for k, _ := range a{
keys = append(keys,k) //append会直接增加不需要make
}
sort.Ints(keys)
for _,v := range keys{
fmt.Println(a[v])
} } func main() {
testMapSort()
}
map的反转
a. 初始化一个新map,把key、value互换即可
package main import (
"fmt"
) func testMapReverse(){
//反转要新生成一个map,需要注意字符类型
var a map[string]int
a = make(map[string]int,5) var b map[int]string
b = make(map[int]string,5) a["aaa"] = 1
a["bbb"] = 3 for k,v := range a{
b[v] = k
}
fmt.Println(b) } func main() {
testMapReverse()
}
六、go中的sync包
a. import(“sync”)
b. 互斥锁, var lock sync.Mutex
c. 读写锁, var rwlock sync.RWMutex
读写锁适用范围:读多写少的场景,读写锁是互斥锁性能的100多倍
在读写锁机制下,允许同时有多个读者读访问共享资源,只有写者才需要独占资源。相比互斥机制,读写机制由于允许多个读者同时读访问共享资源,进一步提高了多线程的并发度。
go build --race 可以检查代码里是不是有重复修改数据的点
互斥锁例子:
package main import (
"fmt"
"math/rand"
"sync"
"time"
) var lock sync.Mutex //互斥锁 func testMutx(){ //go build --race 查看有没有竞争关系,编译后执行返回
//互斥锁同一时间只有一个执行
var a map[int]int
a = make(map[int]int,100) a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
for i := 0; i < 50 ; i++{
go func(b map[int]int){
lock.Lock() //多个goroutine同时修改同一份数据需要互斥锁
b[0] = rand.Intn(100)
lock.Unlock()
}(a)
}
lock.Lock()
fmt.Println(a)
lock.Unlock() time.Sleep(time.Second * 1)
} func main() { testMutx() }
读写锁例子:
sync/atomic 这个方法保证是原子操作(串行)
package main import (
"sync"
//"math/rand"
"fmt"
"sync/atomic"
"time"
) var lock sync.Mutex
var rwlock sync.RWMutex
//读写锁适用于读多写少的场景
//设置3秒,读写锁执行22万次,互斥锁执行2292次
//go get xx下载第三方包,默认会下载到gopath的src下 func testRwlock(){
var a map[int]int
a = make(map[int]int)
var count int32
a[0] = 10
a[1] = 10
a[2] = 10
a[3] = 10
a[4] = 10 for i := 0; i < 2 ; i++{
go func(b map[int]int){
//lock.Lock()
rwlock.Lock()
//b[0] = rand.Intn(100)
time.Sleep(3 * time.Millisecond)
rwlock.Unlock()
lock.Unlock()
}(a)
} for i := 0; i < 100 ; i++{
go func(b map[int]int){
//lock.Lock()
for {
//lock.Lock()
rwlock.RLock()
//fmt.Println(a)
time.Sleep(time.Millisecond)
rwlock.RUnlock()
//lock.Unlock()
atomic.AddInt32(&count,1) //atomic原子操作,相当于串行
}
}(a)
} time.Sleep(time.Second * 3)
fmt.Println(atomic.LoadInt32(&count)) //原子操作 } func main() {
testRwlock()
}
练习
实现一个冒泡排序:
冒泡排序定义:
package main import "fmt"
//切片是变长,数组是固定长度
//冒泡循环两层循环,第二个每次都从后往前确定一个值
func bsSort(a []int){
for i := 0;i < len(a);i++{
//每个元素执行一个冒泡
for j := 1; j < len(a) - i;j++{
if (a[j] < a[j-1]){ //当前值 小于 上一个值就交换位置
a[j],a[j-1] = a[j-1],a[j]
}
fmt.Println(a)
}
} } func main() {
slice := []int{8,7,5,4,3,10,15} //切片
bsSort(slice)
fmt.Println("finally: ",slice)
} /*
[7 8 5 4 3 10 15]
[7 5 8 4 3 10 15]
[7 5 4 8 3 10 15]
[7 5 4 3 8 10 15]
[7 5 4 3 8 10 15]
[7 5 4 3 8 10 15]
[5 7 4 3 8 10 15]
[5 4 7 3 8 10 15]
[5 4 3 7 8 10 15]
[5 4 3 7 8 10 15]
[5 4 3 7 8 10 15]
[4 5 3 7 8 10 15]
[4 3 5 7 8 10 15]
[4 3 5 7 8 10 15]
[4 3 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
finally: [3 4 5 7 8 10 15]
*/
python实现一个冒泡排序:
L = [3, 5, 6, 7, 8, 1, 2]
for i in range(len(L)-1):
for j in range(len(L)-1-i):
if L[j] >L[j+1]:
L[j], L[j+1] = L[j+1], L[j]
print(L)
实现一个选择排序(从小到大)
package main import "fmt" //选择排序
func selectSort(a []int){
//先选出最小的放到最左面,在一次选择
for i := 0;i < len(a);i++{ //循环整个序列
var min int = i
for j:= i + 1; j < len(a);j++{ //循环从1:最后的序列
if (a[min] > a[j]){ //a[min] > a[j] m为当前值 大于下一个值
min = j
}
fmt.Println(a)
}
a[i],a[min] = a[min],a[i] //选出来的最小值和当前值交换
} } func main() {
slice := []int{8,7,5,4,3,10,15} //切片
selectSort(slice)
fmt.Println("finally: ",slice)
} /*
[8 7 5 4 3 10 15]
[8 7 5 4 3 10 15]
[8 7 5 4 3 10 15]
[8 7 5 4 3 10 15]
[8 7 5 4 3 10 15]
[8 7 5 4 3 10 15]
[3 7 5 4 8 10 15]
[3 7 5 4 8 10 15]
[3 7 5 4 8 10 15]
[3 7 5 4 8 10 15]
[3 7 5 4 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
[3 4 5 7 8 10 15]
finally: [3 4 5 7 8 10 15] */
实现一个插入排序(从小到大)
package main import "fmt" //插入排序 从一个有序的列表里把一个元素插入进去
func insertSort(a []int){ //一个数组是有序的,另外一个数组是无序的,无序的要去有序里比大小
for i := 1;i < len(a);i++{ //这是遍历无序的列表
for j := i; j > 0 ;j--{ //这是遍历有序的列表 进行比较插入,无序列表越来越少 ,有序的列表是插入形式,依次增加
if (a[j] > a[j-1]){ //当前值 大于下一个值就终止
break
}
a[j],a[j-1] = a[j-1],a[j]
fmt.Println(a)
}
} } func main() {
slice := []int{8,7,5,4,3,10,15} //切片
insertSort(slice)
fmt.Println("finally: ",slice)
} /*
7 8 5 4 3 10 15]
[7 5 8 4 3 10 15]
[5 7 8 4 3 10 15]
[5 7 4 8 3 10 15]
[5 4 7 8 3 10 15]
[4 5 7 8 3 10 15]
[4 5 7 3 8 10 15]
[4 5 3 7 8 10 15]
[4 3 5 7 8 10 15]
[3 4 5 7 8 10 15]
finally: [3 4 5 7 8 10 15] */
实现一个快速排序(从小到大)
package main import "fmt"
//快速排序
func qSort(a []int,left,right int){
//选中一个值左面的比他小,右面的比他大
if left >= right{ //判断传入是否合法
return
} val := a[left]
k := left for i := left + 1 ; i <= right;i++{ //循环当前序列,即使被切割也是切割序列
if a[i] < val{//val是中间值,如果比val小就要放到val的左面
a[k] = a[i] //将小的数与中间值的位置交换
a[i] = a[k+1]//在将小的位置,与k的下一位交换
a[k+1] = val //将k+1的位置赋值给中间值
k++ //最终更换了一个位置所以要+1
} }
//a[k] = val
qSort(a,left,k-1) //在左面再次排序
qSort(a,k+1,right)//右面再次排序递归
} func main() { slice := []int{8,7,5,4,3,10,15,20,2} //切片
qSort(slice,0,len(slice)-1)
fmt.Println("finally: ",slice) } /*
finally: [2 3 4 5 7 8 10 15 20]
*/
补充:
1、有些时候需要进行多个赋值操作,由于Go里面没有,
操作符,那么可以使用平行赋值i, j = i+1, j-1
2、关于Slice定义:
当切片的索引范围大于len() 但是小于cap()的值,会读取原数组的 隐藏值进行填充
package main import "fmt" func printSlice(v []int){
fmt.Printf("slice is %v , len=(%d),cap=(%d)",v,len(v),cap(v) ) } func main(){
a := []int{1,2,3,4,5,6,7,8,9}
printSlice(a) b := a[2:6]
printSlice(b)
fmt.Println("before slice is\n",b)
c := b[4:6]
printSlice(c)
fmt.Println("after slice is\n",c)
} """
slice is [1 2 3 4 5 6 7 8 9] , len=(9),cap=(9)
slice is [3 4 5 6] , len=(4),cap=(7)
before slice is [3 4 5 6]
slice is [7 8] , len=(2),cap=(3)
after slice is [7 8] 正常应该认为是7 但是有隐藏值 8,9,10 """
Go-day04的更多相关文章
- Spring day04笔记(SVN讲解和回顾昨天知识)
spring day03回顾 事务管理 基于xml配置 1.配置事务管理器 jdbc:DataSourceTransactionManager hibernate:HibernateTransacti ...
- day04 Java Web 开发入门
day04 Java Web 开发入门 1. web 开发相关介绍 2. web 服务器 3. Tomcat服务器启动的问题 4. Tomcat目录结构 5. Web应用程序(虚拟目录映射,缺省web ...
- python day04笔记总结
2019.4.1 S21 day04笔记总结 昨日内容补充 1.解释器/编译器 1.解释型语言.编译型语言 2.解释型:写完代码后提交给解释器,解释器将代码一行行执行.(边接收边解释/实时解释) 常用 ...
- Python基础(函数部分)-day04
写在前面 上课第四天,打卡: 加勒比海盗今天上映:端午节公司发的粽子很有范! 一.函数的基本概念 - 函数是什么? 函数,就是一个'锤子',一个具有特定功能的'锤子',使用者可以在适当的时候使用这个 ...
- day04(权限修饰符,内部类,局部内部类,匿名内部类)
权限修饰符, Public >protected >default > private public 公共权限 随便都可以访问 protected 子类可以访问权限 (子类 ...
- Day04 dom详解及js事件
day04 dom详解 DOM的基础 Document对象 Element对象 Node对象 innerHTML 事件处理 表单验证 上次课内容回顾: JS中ECMAScript用法: JS定义变 ...
- python开发学习-day04(迭代器、生成器、装饰器、二分查找、正则)
s12-20160123-day04 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- 2017-2018-1 JAVA实验站 冲刺 day04
2017-2018-1 JAVA实验站 冲刺 day04 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 找背景音乐 100% 张浩林 游戏操作说 ...
- python s13 day04
1.1 all() 和 any( ) all() any() 0,None,"", [], (),{} #布尔值为0的 列举,None ,空列表,空元祖,空. print( ...
- Java编程基础阶段笔记 day04 Java基础语法(下)
day04 Java基础语法 (下) 笔记Notes要点 switch-case语句注意 switch-case题目(switchTest5) 循环执行顺序 if-else 实现3个整数排序 Stri ...
随机推荐
- 包packages
packages里面如何跨模块导入路径: print(dir()) 可以看到__file__ print(os.path.abspaht(__file__)) 可以看到当前绝对路径 import sy ...
- Upload Files In ASP.NET Core 1.0 (Form POST And JQuery Ajax)
Uploading files is a common requirement in web applications. In ASP.NET Core 1.0 uploading files and ...
- Nginx 如何处理上游响应的数据
陶辉93 一个非常重要的指令 proxy_buffer_size 指令限制头部响应header最大值 proxy_buffering 指令主要是指 上游服务器是否接受完完整包体在处理 默认是on 也就 ...
- Maven使用(一)—— Maven的安装与全局配置
一.Maven安装 Maven的安装步骤: 1.Maven官网(http://maven.apache.org/)下载压缩包,解压缩,当前最新版本是apache-maven-3.5.3-bin.zip ...
- 大学jsp实验3include指令的使用
1.include指令的使用 (1)编写一个名为includeCopyRight.jsp的页面,页面的浏览效果如下: 要求“2016”这个值可以实现动态更新.请写出页面代码: <%@ page ...
- Odoo
doc 文档 Technical Memento(pdf)是一个简短的参考,有点过时,但仍然不能错过. 目前的官方文档由研发团队积极维护. Nicolas Bessi撰写的新API指南可以提供官方文档 ...
- Hdoj 1007 Quoit Design 题解
Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...
- 【CF487E】Tourists(圆方树)
[CF487E]Tourists(圆方树) 题面 UOJ 题解 首先我们不考虑修改,再来想想这道题目. 我们既然要求的是最小值,那么,在经过一个点双的时候,走的一定是具有较小权值的那一侧. 所以说,我 ...
- poj 3666 Making the Grade(离散化+dp)
Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more tha ...
- PyCharm创建自定义代码段(JetBrains系列通用)
创建自定义代码段或者修改代码段:(用习惯了VSCode的main格式,固而改下)