今日概要:

  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的更多相关文章

  1. Spring day04笔记(SVN讲解和回顾昨天知识)

    spring day03回顾 事务管理 基于xml配置 1.配置事务管理器 jdbc:DataSourceTransactionManager hibernate:HibernateTransacti ...

  2. day04 Java Web 开发入门

    day04 Java Web 开发入门 1. web 开发相关介绍 2. web 服务器 3. Tomcat服务器启动的问题 4. Tomcat目录结构 5. Web应用程序(虚拟目录映射,缺省web ...

  3. python day04笔记总结

    2019.4.1 S21 day04笔记总结 昨日内容补充 1.解释器/编译器 1.解释型语言.编译型语言 2.解释型:写完代码后提交给解释器,解释器将代码一行行执行.(边接收边解释/实时解释) 常用 ...

  4. Python基础(函数部分)-day04

    写在前面 上课第四天,打卡: 加勒比海盗今天上映:端午节公司发的粽子很有范! 一.函数的基本概念 - 函数是什么?  函数,就是一个'锤子',一个具有特定功能的'锤子',使用者可以在适当的时候使用这个 ...

  5. day04(权限修饰符,内部类,局部内部类,匿名内部类)

    权限修饰符, Public  >protected >default > private public 公共权限   随便都可以访问 protected  子类可以访问权限  (子类 ...

  6. Day04 dom详解及js事件

    day04 dom详解 DOM的基础 Document对象 Element对象 Node对象 innerHTML 事件处理 表单验证   上次课内容回顾: JS中ECMAScript用法: JS定义变 ...

  7. python开发学习-day04(迭代器、生成器、装饰器、二分查找、正则)

    s12-20160123-day04 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  8. 2017-2018-1 JAVA实验站 冲刺 day04

    2017-2018-1 JAVA实验站 冲刺 day04 各个成员今日完成的任务 小组成员 今日工作 完成进度 张韵琪 写博客.进行工作总结 100% 齐力锋 找背景音乐 100% 张浩林 游戏操作说 ...

  9. python s13 day04

    1.1 all() 和 any( )   all() any()   0,None,"", [], (),{} #布尔值为0的 列举,None ,空列表,空元祖,空. print( ...

  10. Java编程基础阶段笔记 day04 Java基础语法(下)

    day04 Java基础语法 (下) 笔记Notes要点 switch-case语句注意 switch-case题目(switchTest5) 循环执行顺序 if-else 实现3个整数排序 Stri ...

随机推荐

  1. 包packages

    packages里面如何跨模块导入路径: print(dir()) 可以看到__file__ print(os.path.abspaht(__file__)) 可以看到当前绝对路径 import sy ...

  2. 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 ...

  3. Nginx 如何处理上游响应的数据

    陶辉93 一个非常重要的指令 proxy_buffer_size 指令限制头部响应header最大值 proxy_buffering 指令主要是指 上游服务器是否接受完完整包体在处理 默认是on 也就 ...

  4. Maven使用(一)—— Maven的安装与全局配置

    一.Maven安装 Maven的安装步骤: 1.Maven官网(http://maven.apache.org/)下载压缩包,解压缩,当前最新版本是apache-maven-3.5.3-bin.zip ...

  5. 大学jsp实验3include指令的使用

    1.include指令的使用 (1)编写一个名为includeCopyRight.jsp的页面,页面的浏览效果如下: 要求“2016”这个值可以实现动态更新.请写出页面代码: <%@ page ...

  6. Odoo

    doc 文档 Technical Memento(pdf)是一个简短的参考,有点过时,但仍然不能错过. 目前的官方文档由研发团队积极维护. Nicolas Bessi撰写的新API指南可以提供官方文档 ...

  7. Hdoj 1007 Quoit Design 题解

    Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...

  8. 【CF487E】Tourists(圆方树)

    [CF487E]Tourists(圆方树) 题面 UOJ 题解 首先我们不考虑修改,再来想想这道题目. 我们既然要求的是最小值,那么,在经过一个点双的时候,走的一定是具有较小权值的那一侧. 所以说,我 ...

  9. poj 3666 Making the Grade(离散化+dp)

    Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more tha ...

  10. PyCharm创建自定义代码段(JetBrains系列通用)

    创建自定义代码段或者修改代码段:(用习惯了VSCode的main格式,固而改下)