Golang のマップの基礎となるデータ構造
導入
Golang プログラミング言語では、map
これは重要で一般的に使用されるデータ構造です。これは、キーと値のペアを保存および取得するための便利な方法を提供します。golang
この記事では、基礎となるデータ構造を深く掘り下げてmap
理解し、使用できるようにします。
map
基本概念
map
順序なしのコレクション型であり、キーと値のペアで構成されます。各キーは一意ですが、値は繰り返すことができます。map
ハッシュ テーブルに基づいて実装されているため、ほとんどの操作でパフォーマンスが非常に効率的になります。
map
基礎となる実装
ではgolang
、map
基礎となるデータ構造はハッシュ テーブルです。ハッシュ テーブルはバケット配列とハッシュ衝突リンク リストで構成されます。map
キーと値のペアを挿入すると、最初にキーのハッシュ値が計算され、次にキーと値のペアが対応するバケットに保存されます。
ハッシュ競合の解決
ハッシュ関数の制限により、異なるキーが同じハッシュ値を生成する場合があり、これをハッシュ衝突と呼びます。基礎となる実装ではmap
、ハッシュの競合の問題を解決するためにリンク リストが使用されます。ハッシュの衝突が発生すると、新しいキーと値のペアがリンク リストの先頭に追加されます。
map
読み取りおよび書き込み操作
map
読み取りおよび書き込み操作は非常に効率的です。検索操作を実行するときは、最初にキーのハッシュ値が計算され、次にハッシュ値を通じて対応するバケットが検索されます。次に、バケットに対応するリンク リストで線形検索を実行して、対応するキーと値のペアを見つけます。
map
キーと値のペアを挿入すると、キーのハッシュ値も計算され、対応するバケットが見つかり、新しいキーと値のペアがリンク リストの先頭に挿入されます。
map
性能特性
map
そのパフォーマンス特性は次のとおりです。
-
読み取り操作の時間計算量は O(1) で、これは定数時間です。 -
挿入および削除操作の時間計算量も O(1) です。 -
map
サイズは動的に変化し、必要に応じて自動的に拡大または縮小されます。
予防
使用するmap
際には次のような注意点があります。
-
map
これは順序付けされていません。つまり、走査の順序が挿入の順序と同じであるという保証はありません。 -
map
的键必须是可比较的类型,例如int
、string
、float64
等,而值则可以是任意类型。 -
当通过键来访问 map
中的值时,如果该键不存在,map
会返回值类型的零值。
源码解析
runtime/map.go
map
的底层数据结构源码位于runtime/map.go
文件中。在该文件中,定义了hmap
结构体,它表示map
的底层哈希表。
type hmap struct {
count int
flags uint8
B uint8
noverflow uint16
hash0 uint32
buckets unsafe.Pointer
oldbuckets unsafe.Pointer
nevacuate uintptr
extra *mapextra
}
哈希表的桶结构
哈希表的桶结构定义如下:
type bmap struct {
tophash [bucketCnt]uint8
keys [bucketCnt]keytype
values [bucketCnt]valuetype
}
其中,tophash
数组存储了每个键值对的哈希值的低8位,用于快速定位桶中的键值对。keys
数组和values
数组分别存储了键和值的实际数据。
哈希冲突解决
在map
的哈希表中,当多个键的哈希值相同时,会发生哈希冲突。为了解决哈希冲突,Golang采用了链地址法。每个桶的tophash
数组中的元素存储了相同哈希值的键值对在链表中的位置。
数据访问和修改
在访问map
的键值对时,首先会通过哈希函数计算键的哈希值,然后根据哈希值找到对应的桶。接着,在桶的链表中进行线性查找,找到目标键值对。
当向map
中插入新的键值对时,会按照相同的过程计算哈希值,并将键值对插入到对应的桶中。
扩容和缩容
map
的大小是动态变化的。当map
中的键值对数量达到一定阈值时,会触发扩容操作。扩容操作会创建一个新的哈希表,并将原有的键值对重新分配到新的桶中。
相反,当键值对的数量减少时,也可能触发缩容操作。缩容操作会将键值对重新分配到更小的哈希表中。
写在最后
感谢大家的阅读,晴天将继续努力,分享更多有趣且实用的主题,如有错误和纰漏,欢迎给予指正。 更多文章敬请关注作者个人公众号 晴天码字
本文由 mdnice 多平台发布