Go语言的内置容器

news/2024/11/8 15:44:16 标签: golang, 算法, 开发语言

文章目录

  • 一、数组
      • 数组的定义
      • 数组声明
      • 数组特点
      • 数组元素修改
  • 二、切片
      • 切片声明
      • 基于数组创建切片
      • 使用make()函数构造切片
      • 使用append()为切片动态添加元素\
      • 使用copy()复制新的切片
      • 数组与切片相互转换
  • 三、Map映射
      • Map定义
      • 使用make()函数创建map
      • 用切片作为map的值
      • 使用delete()函数删除元素

一、数组

数组的定义

一个由固定长度的特定元素组成的序列

数组声明

标准格式声明数组:

var variable_name [size]type

初始化数组:

var variable_name = [size]type{value,...}

编译器自行推断数组大小:

var variable_name = [...]type {value,...}

一些示例:

//示例1
var a [3] int  //声明一个数组为 a ,类型为int,大小为3的数组
a[0] = 12 //为第一个元素填充数据,为12
a[1] = 13 //为第二个元素填充数据,为13
a[2] = 14 //为第三个元素填充数据,为14

//示例2
var a = [3] int {12,13,14} //定义且声明数组内容


//示例3
a := [3]int {12,13,14}//定义且声明数组内容

//示例4
a := [3]int{12}//可以只填充部分数据

//示例5
a := [3]int {1:13,2:14}//填充指定位置

//示例6
a := [...]int{12,13,14}//编译器自行判断数组长度

数组特点

  • 数组的每个元素可以通过索引下标来访问
  • 索引下标的范围从0开始到数据长度减1结束
  • 数组无法灵活扩容:在定义数组元素数量后,赋值元素变量个数必须要小于或者等于预设值的元素数量
  • type指任意的基本类型,也可以是数组本身,实现多维数组
  • 在Go语言中数组是值类型而不是引用类型
  • 这意味着当数组变量被赋值时,将会获得原数组的拷贝,新数组中元素的改变不会影响原数组中元素的值

示例:

package main
import "fmt"
func main() {
    a := [...]int{12, 78, 50}
    b := a	// 将a数组复制给b数组
    b[0] = 60
    fmt.Println(a)
    fmt.Println(b)
}

//运行结果为:
//[12 78 50]
//[60 78 50]

数组元素修改

package main
import "fmt"
func main() {
	var a [1]string                          //定义一个1个元素的string类型数组,string默认值为空
	var b = [2]string{“a”, “b”}  //定义一个2个元素的string类型数组
	c := [3]string{"a", "b", "c"}         //定义并初始化一个3个空间的string类型数组
	d := [...]string{"a", "b", "c", "d"} //自动推到元素个数
	e := d                                        //拷贝数组
	e[0] = "e"                                  //修改数组指定位置的值
	fmt.Println(a, len(a))                 //打印a数组、a数组长度
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d, len(d))
	fmt.Println(e, len(e))
}



//运行结果为:
//[] 1
//[a b]
//[a b c]
//[a b c d] 4
//[e b c d] 4

二、切片

数组和切片的对比
在这里插入图片描述

切片声明

切片声明:

var name[]type = []type{......}

切片特点:

  • []中不需要指定长度,即长度是不固定的
  • 可以追加元素,在追加时可能使切片的容量增大,可以从数据中生成新的切片或者是声明新的切片

示例:

package main
import "fmt"
func main() {
    var a []int= []int{10,11,12,13}
    fmt.Println(a,len(a))
}



//运行结果为:
//[10 11 12 13] 4

基于数组创建切片

var name [] type = 数组名[开始位置:结束位置]

特点:

  • 结束位置的元素不取
  • 切片数量 = 结束位置下标 - 开始位置下标
  • 当缺省开始位置时,表示从连续的区域开头到结束位置
    在编程和数据处理领域,"缺省"(或“默认”)通常指的是在没有明确指定某个值或选项时,系统或程序将自动采用的一个预设值或行为。这个预设值或行为被称为“缺省值”或“默认值”。
  • 当缺省结束位置时,表示从开始位置到整个连续区域末尾
  • 两者同时缺省时,与数组本身等效
  • 两者同时为0时,等于空切片,一般用于切片复位

示例:


//示例1
package main
import "fmt"
func main() {
    a := [5]string{"A","B","C","D"}
    var b []string = a[1:2]
    fmt.Println(a)
    fmt.Println(b,len(b))
}


//运行结果为:
//[A B C D ]
//[B] 1


//示例2
package main
import "fmt"
func main() {
    a := [5]int{76, 77, 78, 79, 80}
    var b []int = a[1:3]	//取a数组的第1到第3个元素
    var c []int = a[:3]	//取a数组的第0到第3个元素
    var d []int = a[1:]	//取a数组的第1到最后一个元素
    var e []int = a[:]	//取a数组的第0到最后一个元素
    var f []int = a[0:0]	//空切片
    fmt.Println(a,len(a))
    fmt.Println(b,len(b))
    fmt.Println(c,len(c))
    fmt.Println(d,len(d))
    fmt.Println(e,len(e))
    fmt.Println(f,len(f))
}



//运行结果为:
//[76 77 78 79 80] 5
//[77 78] 2
//[76 77 78] 3
//[77 78 79 80] 4
//[76 77 78 79 80] 5
//[] 0

  • 切片本身不包含任何数据
  • 切片是底层数组的一个上层表示
  • 对切片进行的任何修改都将反映在底层数据化中
package main
import "fmt"
func main() {
    a := [5]string{"A","B","C","D","E"}
    var b []string = a[1:3]
    fmt.Println("修改前的a数组:",a)
    fmt.Println("修改前的b切片:",b)
    b[1]="2"
    fmt.Println("修改后的a数组:",a)
    fmt.Println("修改后的b切片:",b)
}



//运行结果为:
//修改前的a数组: [A B C D E]
//修改前的b切片: [B C]
//修改后的a数组: [A B 2 D E]
//修改后的b切片: [B 2]

  • 切片的长度是指切片中元素的个数
  • 切片的容量是指从切片的起始元素开始到其底层数组中的最后一个元素的个数
  • 切片的长度可以动态的改变(最大为其容量)
  • 任何超出最大容量的操作都会发生运行时错误
package main
import (
    "fmt"
)
func main() {
    a := [...]string{"A", "B", "C", "D", "E"}
    b := a[1:3]
    fmt.Printf("数组a长度为:%d \n切片b容量为:%d", len(a), cap(b))
}



//运行结果为:
//数组a长度为:5 
//切片b容量为:4

使用make()函数构造切片

var name [] type = make([]type,size,cap)

特点:

  • type指切片元素类型
  • size 指的是为这个类型分配多少个元素
  • cap 为预分配的元素数量
  • cap设定后不会影响 size,只是为了提前分配空间,降低多次分配空间造成的性能问题
package main
import "fmt"
func main() {
    var a [] int =make([]int,5,10)
//创建一个切片,初始元素个数为5,并预留10个元素的存储空间
    a[0]=10
    a[4]=14
    fmt.Println("切片内容:", a)
    fmt.Println("切片长度:", len(a))
    fmt.Println("切片容量:", cap(a))
}



//运行结果为:
//切片内容: [10 0 0 0 14]
//切片长度: 5
//切片容量: 10

使用append()为切片动态添加元素\

append(name,value)
append(name,[]type[value,value,value]...)

特点:

  • 可以为切片追加单个或多个元素;或者是追加切片
  • 使用append()函数为切片动态添加元素时,如果空间不足以容纳足够多的元素,切片就会进行“扩容”,此时新切片的长度会发生改变。
  • 扩展容量小于1024个元素时按当前切片的容量(Cap)2倍扩容,扩展容量大于1024个元素时按Cap的1/4扩容。
package main
import“fmt”
func main() {
    a := []int{10, 20, 30, 40, 50}
    b := a[1:3]
    fmt.Println(a)
    fmt.Println(b)
    b = append(b, 60)
    fmt.Printf(“第一次追加后,切片a为:%d 切片a容量为:%d\n", a, cap(a))
    fmt.Printf(“第一次追加后,切片b为:%d 切片b容量为:%d\n", b, cap(b))
    b = append(b, 70,80,90,100)
    fmt.Printf(“第二次追加后,切片a为:%d 切片a容量为:%d\n", a, cap(a))
    fmt.Printf(“第二次追加后,切片b为:%d 切片b容量为:%d\n", b, cap(b))
}



//运行结果为:
//[10 20 30 40 50]
//[20 30]
//第一次追加后,切片a为:[10 20 30 60 50] 切片a容量为:5
//第一次追加后,切片b为:[20 30 60] 切片b容量为:4
//第二次追加后,切片a为:[10 20 30 60 50] 切片a容量为:5
//第二次追加后,切片b为:[20 30 60 70 80 90 100] 切片b容量为:8

在对切片 b 进行第一次 append 时,由于它仍然指向 a 的底层数组,因此 a 和 b 共享数据;但第二次 append 超出容量时,切片 b 就会分配新的底层数组,不再共享 a 的数据。

使用copy()复制新的切片

copy(destSlice,srcSlice)

特点:

  • destSlice 为复制的目标切片
  • srcSlice 为数据来源切片
  • 目标切片必须分配过空间且足够承载复制的元素个数,并且来源和目标的类型必须一致。
  • copy() 函数来源切片和目标切片可以共享同一个底层数组,甚至有重叠也没有问题。
package main
import "fmt"
func main() {
    a := []int{0,1,2,3,4,5}
    b := []int{10,11,12}
    fmt.Println(a)
    fmt.Println(b)
    copy(b,a)  // 只会复制a的前3个元素到b中
    fmt.Println(a)
    fmt.Println(b)
}



//运行结果为:
//[0 1 2 3 4 5]
//[10 11 12]
//[0 1 2 3 4 5]
//[0 1 2]

数组与切片相互转换

  • 需要使用[:]将数组伪装为切片类型后再进行赋值,否则无法通过编译
  • 数组与切片中的元素类型必须相同

切片转成数组:

package main
import "fmt"
func main() {
    //切片转成数组
    s := []int{10, 11, 12}
    var a [3]int
    fmt.Println(copy(a[:], s))
    fmt.Println(a)
}


//运行结果为:
//3
//[10 11 12]

数组转成切片:

package main
import "fmt"
func main() {
    //数组转成切片
    a := [...]int{10, 11, 12}
    b := make([]int, 3)
    fmt.Println(copy(b, a[:]))
    fmt.Println(b)
}



//运行结果为:
//3
//[10 11 12]

三、Map映射

Map定义

一种无序的Key/value的集合
能够通过key值快速检索数据值
map这种数据结构在其他编程语言中也称为字典、映射或哈希表。
Golang的map由两种重要的结构构成:hmap和bmap

声明map集合:

var name map[key_type]value_type

语法说明如下:

  1. name为map变量名
  2. key_type为键类型
  3. value_type为键值对应值类型
package main
import "fmt"
func main() {
    a:=map[int]string{
        110:"报警电话",
        120:"急救电话",
        119:"消防电话"}
    fmt.Println(a)
}



//运行结果为:
//map[110:报警电话 119:消防电话 120:急救电话]

使用make()函数创建map

make(map[KeyType]ValueType, [cap])

特点:

  • map可以在声明的时候填充元素,也可以单独填充元素
  • map中的数据都是成对出现的
  • map类型的变量默认初始值为nil
  • 其中cap表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map的时候就为其指定一个合适的容量。

用切片作为map的值


//示例1

package main
import "fmt"
func main() {
    a := make(map[string]int,10)
    a["报警电话"] = 110;
    a["急救电话"] = 120;
    a["火警电话"] = 119;
    fmt.Println(a)
}




//运行结果为:
//map[急救电话:120 报警电话:110 火警电话:119]


//示例2
package main
import "fmt"
func main() {
    //map的值为切片:
    a := make(map[int][]string, 2)// 创建一个容量为 2 的 map,键为 int,值为 []string(切片)
    a[1] = make([]string, 0, 2)      // 为键 1 初始化一个长度为 0、容量为 2 的切片
    a[1] = append(a[1], "A", "a") // 向切片中追加元素 "A" 和 "a"
    fmt.Println(a)
}


//运行结果为:
//map[1:[A a]]


//示例3
package main
import "fmt"
func main() {
   //切片的元素类型为map:
    b := make([]map[string]int, 2)
    b[0] = make(map[string]int, 2)
    b[0]["A"] = 1
    b[0]["a"] = 2
    fmt.Println(b)
}






//运行结果为:
//[map[A:1 a:2] map[]]

使用delete()函数删除元素

delete(map,key)

特点:

  • 如果要删除的key不存在,那么这个调用将什么都不发生,也不会有什么副作用
  • 但是如果传入的map变量的值是nil,该调用将导致程序抛出异常(panic)
示例
package main
import "fmt"
func main() {
    a:=map[int]string{
        110:"报警电话",
        120:"急救电话",
        119:"消防电话"}
    delete(a,110)
    fmt.Println(a)
}


//运行结果为:
//map[119:消防电话 120:急救电话]


http://www.niftyadmin.cn/n/5744086.html

相关文章

YOLOv11改进:SE注意力机制【注意力系列篇】(附详细的修改步骤,以及代码,与其他一些注意力机制相比,不仅准确度更高,而且模型更加轻量化。)

如果实验环境尚未搭建成功,可以参考这篇文章 ->【YOLOv11超详细环境搭建以及模型训练(GPU版本)】 文章链接为:YOLOv11超详细环境搭建以及模型训练(GPU版本)-CSDN博客 -------------------------------…

一篇Spring Boot 笔记

一、Spring Boot 简介 Spring Boot 是一个用于创建独立的、基于 Spring 的生产级应用程序的框架。它简化了 Spring 应用的初始搭建和开发过程,通过自动配置等功能,让开发者能够快速地构建应用,减少了大量的样板代码和复杂的配置。 二、核心特…

100种算法【Python版】第59篇——滤波算法之扩展卡尔曼滤波

本文目录 1 算法步骤2 算法示例2.1 示例描述2.2 python代码3 算法应用:机器人位姿估计扩展卡尔曼滤波(EKF)是一种处理非线性系统的状态估计算法。它通过线性化非线性系统来实现类似于线性卡尔曼滤波的效果。 1 算法步骤 (1)初始化 初始状态: x ^ 0 ∣ 0 \hat{x}_{0|0}

《XGBoost算法的原理推导》12-14决策树复杂度的正则化项 公式解析

本文是将文章《XGBoost算法的原理推导》中的公式单独拿出来做一个详细的解析,便于初学者更好的理解。 我们定义一颗树的复杂度 Ω Ω Ω,它由两部分组成: 叶子结点的数量;叶子结点权重向量的 L 2 L2 L2范数; 公式(…

代码随想录之字符串刷题总结

目录 1.反转字符串 2.反转字符串II 3.替换数字 4.翻转字符串里面的单词 5.右旋&&左旋字符串 1.反转字符串 题目描述: 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外…

十五:java web(7)-- Spring Boot

目录 1. Spring Boot 简介 1.1 简介 1.2 Spring Boot 的特点 1.3 Spring Boot 和 Spring 的关系 2. Spring Boot 快速入门 2.1 创建第一个 Spring Boot 项目 3. Spring Boot 配置管理 3.1 application.properties 和 application.yml 配置 这两种都可以 好像现在更推荐…

计算机网络——TCP篇

TCP篇 基本认知 TCP和UDP的区别? TCP 和 UDP 可以使用同一个端口吗? 可以的 传输层中 TCP 和 UDP在内核中是两个完全独立的软件模块。可以根据协议字段来选择不同的模块来处理。 TCP 连接建立 TCP 三次握手过程是怎样的? 一次握手:客户端发送带有 …

VMware 虚拟机使用教程及 Kali Linux 安装指南

VMware 虚拟机使用教程及 Kali Linux 安装指南 在现代计算机科学与网络安全领域,虚拟化技术的应用越来越广泛。VMware 是一款功能强大的虚拟化软件,可以帮助用户在同一台物理机上运行多个操作系统。本文将详细介绍如何使用 VMware 虚拟机,并…