美文网首页
第二节数据结构

第二节数据结构

作者: barriers | 来源:发表于2019-12-21 20:58 被阅读0次

    1数组

    1.定义数组的格式:var argName = [n] type,n>=0 如 var data = [5] int;
    2.数组长度也是类型的一部分,因此具有不同长度的数据为不同类型;
    3.注意区分指向数组的指针和指针数组;
    4.数组在go中为值类型;
    5.数组之间可以使用==或!=进行比较,但不能使用大小与比较;
    6.可以使用new来创建数组,此方法返回一个指向数组的指针;
    7.go支持多维数组
    8.定义二维数组: var arr [2][3]int,var arr [2][3]int {{1,2,3},{,6,7,8}}

    因为不同长度的数组为不同类型,所以不同长度的数组之间不能直接用=赋值。可以用循环赋值,定义数组的时候就给数组赋值:a:= [2] int{1,1}则a为[1,1],若为a:= [2] int{1}则a为[1,0]
    定义多维数组时:最外层可以省略为几维数组,而最内层不能省略,如a := [...][3] int{{1:1},{2:2}};
    用var声明数组变量时数据类型后面可以不接{},而用冒号形式声明的必须接{}
    定义数组时,可以省略[]内的...或者数字,系统会自动根据{}数据的个数进行推导

    import (
        "fmt"
    )
    
    func main (){
        a := [2] int{1,2}
        // 输出[1,1]
        fmt.Println(a)
        a := [2] int{1}
        // 输出[1,0]
        fmt.Println(a)
        a := [20] int{19:2}
        // 输出前19个元素为0,第20个(下标为19)为2
        fmt.Println(a)
        a := [...] int{1,2,3,4,5}
        // 输出[1,2,3,4,5]
        fmt.Println(a)
        
        // 指向数组的指针
        a := [...] int{99:5}
        // 将a的地址赋值给p指针
        var p *[100]int = &a
        // 输出前99个为0,第一百个为5的数组,数组前有&;&[0,0...,5]
        fmt.Println(p)
    
        // 指针数组
        x, y := 1,2
        // 将x,y的地址赋值给a,a为int型指针数组,实际上保存的是指针
        a := [...] *int{&x, &y}
        fmt.Println(a)
    
        // 用new创建指向数组的指针
         p := new([10] int)
        // 输出10个为0的数组,数组前有&;&[0,0...,5],表示为指向数组的指针
        fmt.Println(p)
         // 对下标为1的位置赋值为2
         p[1] = 2
    
         // 多维数组
        a := [2][3] int{{1,1,2},{2,2,1}}
        // 输出[[1,1,2,][2,2,1]]
        fmt.Println(a)
        a := [2][3] int{{1:1},{2:2}}
        // 输出[[0,1,0,][0,0,2]]
        fmt.Println(a)
        // 最外层可以省略为几维数组,而最内层不能省略
        a := [...][3] int{{1:1},{2:2}}
        // 输出[[0,1,0,][0,0,2]]
        fmt.Println(a)
    }
    
    func main(){
    // 从第一位开始将最大的向最后一位冒
      var b = [6] int {5,8,6,1,7,3}
        length := len(b)
            for i:=0;i<length;i++{
                for j:=1;j<length-i;j++{
                    if b[j]<b[j-1]{
                        tem:=b[j]
                        b[j] = b[j-1]
                        b[j-1] = tem
                    }
                }
            }
        fmt.Println(b)
    //从第i加一个开始将最小的向前面冒
    b = [6] int {5,8,6,1,7,3}
    for i:=0;i<length;i++{
        for j:=i+1;j<length;j++{
            if b[j]<b[i]{
                tem:=b[j]
                b[j] = b[i]
                b[i] = tem
            }
        }
    }
    fmt.Println(b)
    }
    

    数组遍历

    用 for key,value:=range nums遍历数组,改变value的值并不会改变nums中的值,value只是定义的一个变量,每次循环将对应key的值赋值给变量value

    import (
        "fmt"
    )
    
    func main(){
        // 声明数组
        nums := [10] int {1,2,3,4,5}
        for i:=0;i<len(nums);i++{
            fmt.Println("i", i, "value", nums[i])
        }
    
        for key,value:=range nums{
            fmt.Println("key", key, "value", value)
        }
    }
    

    2.1切片

    1.切片本身并不是数组,它指向底层的数组;
    2.作为变长数组的替代方案,可以关联底层数组的局部或全部;
    3.为引用类型;
    4.可以直接创建或从底层数组获取生成;
    5.使用len()获取元素个数,cap()获取容量;
    6.一般使用make()创建
    7.如果多个slice指向相同底层数组,其中一个的值改变会影响全部;

    s:=[]int{10,20,30,40,50}
    # s[0:3:5]表示截取s数组下标0-2的数据,截取的容量为5
    slice := s[0:3:5]
    

    切片创建形式:make([]type,len,cap),其中cap可以省略,则和len的值相同,len表示存数的元素个数,cap表示容量,type为类型,int等。
    容量表示本切片最多可以容纳多少个元素,如果超过这个容量,则系统会自动重新分配一个2倍容量的地址供使用,如果不够就以1倍,2倍,4倍,8倍这样的扩展下去,因为重新分配地址很耗性能,故通常先定义好。
    切片创建var s1 [] int,[]中为空就表示为切片,为...或数字表示为数组
    切片的下标都py一样是前闭后开,也可以用[5:],[:5]进行切片
    go中数组是定长的,切片可以看成一种变长数组。

    import (
        "fmt"
    )
    
    func main(){
        // 声明数组
        var a [2] int
        a = [2] int {1,2}
        // 声明切片
        var s1 [] int
        fmt.Println(s1)
        fmt.Println(a)
    
        b := [10] int{}
    // 切片
        s2 := b[5:10]
        fmt.Println(b)
    // 取单独某个元素
        fmt.Println(b[0])
        fmt.Println(s2)
    
        s3 := make([] int, 3, 10)
        fmt.Println(s3, len(s3), cap(s3))
    }
    

    使用切片需要注意,切片为引用类型,当新添加的元素后的长度大于切片容量,则会重新分配一个切片,容量为之前容量的两倍,此时的切片和之前的切片不是同一个对象。
    示例如下,当s容量大于等于1时,则元素成功添加到切片(因为为引用类型,且不会进行重新分配切片),而此处容量为0,故元素没有添加到s切片(因为重新分配切片,ping里面的s跟pong里面的s已经不是同一个对象了)

    func Ping(s []int){
        s = append(s, 3)
    }
    func Pong(){
        s := make([]int, 0)
        fmt.Println(s)
        Ping(s)
        fmt.Println(s)
    }
    

    2.1.1reslice

    1.Reslice时索引以被切片的切片为准;
    2.索引不可以超过被切片的切片的容量cap()值;
    3.索引越界不会导致底层数组的重新分配而是引发错误

    切片后,切片的容量为所切切片的起始位置到数组的末尾的元素个数,故可以在该切片上进行再次切片,再次切片时索引以被切切片的索引为准,最大下标为该切片的容量,示例如下

    import (
        "fmt"
    )
    
    func main(){
        c := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
        // 切片,sa为[c,d,e]sb为[d,e],sc为[f,g],sa的容量为9(从切片起始位置到原数组末尾)
        sa := c[2:5]
        sb:=sa[1:3]
        sc:=sa[3:5]
        fmt.Println(sa)
    
    }
    

    2.2切片方法

    2.2.1append方法

    1可以在slice尾部追加元素;
    2.可以将一个slice追加在另一个slice尾部;
    3.如果最终长度未超过追加到slice的容量则返回原始slice;
    4.如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据。

    数组不能使用append方法,切片可以;用法 s5 = append(s5, 1, 2, 3)
    在s5切片中追加1,2,3并返回给s5
    当从一个数组中切两个切片,切片元素有重叠部分时,修改一个切片的重叠元素,则另一个也会改变值(因为切片为引用类型,原理跟py的一样),当给一个切片中添加了元素超过它的容量后在修改重叠值,则另一个不会改变(因为当超过了容量时,系统将给切片返回一个新的地址,所以修改不会影响另一个切片)

    import (
        "fmt"
    )
    
    func main(){
        c := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
        // 切片
        sa := c[2:5]
        sb:=sa[1:3]
        fmt.Println(sa)
    
        s5 := make([] int, 3, 6)
        fmt.Println(s5)
        s5 = append(s5, 1, 2, 3)
        fmt.Println(s5)
    
    }
    

    2.2.2copy方法

    用法:copy(to_copy,by_copy);将by_copy这个数组copy给to_copy这个数组

    1.将短数组copy给长数组,则长数组的前n(短数组元素个数)个值将变为短数组的值,后面的继续为之前对应下标的值;s1=[1,2,3],s2=[9,8,7,6,5],copy(s2,s1);则s2变为[1,2,3,6,5]
    2.将长数组copy给短数组,则将只保留长数组的前n(短数组的元素个数)个元素至短数组;s1=[1,2,3],s2=[9,8,7,6,5],copy(s1,s2);则s1变为[9,8,7]
    3.copy(s1[2:3],s2[5:6]) ;将s2下标为5和6的两个元素copy至s1中下标为2和3的位置; s1=[1,2,3],s2=[9,8,7,6,5],copy(s1[1:2],s2[3:4])

    import (
        "fmt"
    )
    
    func main(){
        s1 := []string{"a", "b", "c"}
        // 切片
        s2 := []string{"f", "g", "h", "i", "j", "k"}
        copy(s1,s2)
    
        fmt.Println(s5)
    }
    

    2.2.3切片实现删除方法

    seq := []string{"a", "b", "c", "d", "e"}
    # 删除下标为2的数据
    index := 2
    # 通过再次切片和append实现删除
    seq = append(seq[:index], seq[index+1:]...)
    

    3数组和切片区别

    slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度;如a := [...]int{1,2,3} a := [3]int{1,2,3},而声明slice时,方括号内没有任何字符;如a:= []int{1,2,3} a := make([]int, 5) a := make([]int, 5, 10);。
    可以看见切片初始化时[]是空的,表明是切片类型,而数组中是必须有值的
    当作为参数传递给函数时,数组传递的是值,而切片是地址,因为会将数组整个拷贝一份得到值传递,所以效率不如切片高;

    func changeArray(a [3]int) {
    }
    
    func changeSlice(s []int) {
    }
    

    相关文章

      网友评论

          本文标题:第二节数据结构

          本文链接:https://www.haomeiwen.com/subject/hfpgnctx.html