प्रौद्योगिकी साझेदारी

Go भाषायाः आरम्भार्थं Map इत्यस्य विस्तृतव्याख्यानम्

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Go भाषायाः आरम्भार्थं Map इत्यस्य विस्तृतव्याख्यानम्

1.मूलपरिभाषा

map kv प्रारूपेण कील-मूल्ययुग्मानां अक्रमितसङ्ग्रहः अस्ति

(१) विशेषताः

  • प्रकारविशेषताः : map एकः सन्दर्भप्रकारः अस्ति, अतः फंक्शन् मध्ये मूल्यं अद्यतनं कृत्वा स्थायिरूपेण परिवर्तनं भविष्यति ।
  • क्रमिकलक्षणम् : नक्शा-भ्रमणं अक्रमितम् अस्ति, यतः अधः स्तरः हैश-सारणी अस्ति, तथा च हैश-सारणी अक्रमिता अस्ति ।
  • आरम्भीकरणस्य उपयोगः: 0 मूल्यं अथवा अप्रारम्भितमूल्यं शून्यं भवति, अन्यथा प्रत्यक्षतया आतङ्कितः भविष्यति ।
  • कील-मूल्ययुग्मम् : कील-मूल्यं च सर्वदा युग्मरूपेण दृश्यते, कीलः अद्वितीयः भवति तथा च कोऽपि तुलनीयः प्रकारः भवितुम् अर्हति
  • गतिशीलः : कील-मूल्ययुग्मानि रनटाइम् इत्यत्र गतिशीलरूपेण योजयितुं वा विलोपयितुं वा शक्यन्ते यत्र पूर्वमेव आकारस्य घोषणायाः आवश्यकता नास्ति
  • द्रुत अन्वेषणम् : नक्शा द्रुतं अन्वेषणं, सम्मिलनं, विलोपनं च कार्यं प्रदाति, यस्य औसतसमयजटिलता O(1) भवति ।
  • समवर्ती : सूत्र-सुरक्षितं न, सुरक्षां सुनिश्चित्य तालाबन्दी आवश्यकी भवति

(2) परिभाषा कथन

var name map[key_type]value_type
  • 1
  • name: चर नाम
  • key_type: कीलस्य प्रकारः
  • value_type: मूल्यस्य प्रकारः
// 方式一
var m map[int]string = map[int]string{}

// 方式二
m := map[int]string{
    1 : "老一",
    2 : "老二",
    3 : "老三",
}

// 方式三:5代表容量,也就是在内存中占用多大的空间,可以省略
m := make(map[int]string,5)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.मूलप्रयोगः

(1) तत्त्वानि योजयन्तु

  • 1. सर्वाधिकं सामान्यं विधिः अस्ति यत् अक्षरशः माध्यमेन map घोषयन्ते सति तत् योजयितुं शक्यते, यथा उपरि विधिः 2 दर्शितम् अस्ति ।
  • 2. द्वितीयं सोपानं निर्दिष्टस्य कीलस्य कृते तत्सम्बद्धं मूल्यं प्रत्यक्षतया सेट् कर्तुं भवति ।
mapName[key] = value

// 假设map名为m,key为int,value为string
m[5] = "老五"
  • 1
  • 2
  • 3
  • 4

(2) तत्त्वानि लोपयन्तु

कील-आधारित-तत्त्वानि विलोपयन्तु, अस्तित्वहीन-कील-विलोपनसमये कोऽपि दोषः न निवेदितः भविष्यति ।

delete(mapName, key)  

// 假设map名为m,key为int,value为string
delete(m, 5)
  • 1
  • 2
  • 3
  • 4

(3) तत्त्वान् परिवर्तयतु

परिवर्तनार्थं निर्दिष्टकुंजीसम्बद्धं मूल्यं प्रत्यक्षतया परिवर्तयितुं शक्नुवन्ति ।

mapName[key] = newValue 

// 假设map名为m,key为int,value为string
m[5] = "五"
  • 1
  • 2
  • 3
  • 4

(4) तत्त्वानि प्राप्नुत

कीलस्य अनुसारं मूल्यं प्राप्नुवन्तु, ठीकम् अस्ति ध्वजबिट् अस्ति वा तत् प्राप्तम् अस्ति वा, प्रकारः Boolean अस्ति

यदि मूल्यं न लभ्यते तर्हि कोऽपि दोषः न निवेदितः भविष्यति तथा च तत्सम्बद्धप्रकारस्य शून्यमूल्यं प्रत्यागमिष्यति ।

value, ok := mapName[key]
if !ok {
		fmt.Println(ok)
	}
  • 1
  • 2
  • 3
  • 4

(5) सर्वान् तत्त्वान् भ्रमतु

नोटः- नक्शा-भ्रमणम् अक्रमितम् अस्ति

for key, value := range myMap {
   // 处理每对键值
}

// 例子
for i, s := range m {
		fmt.Println(i, s)
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3. अन्तर्निहितसिद्धान्ताः

गोलाङ्गभाषायां नक्शायाः अन्तर्निहितः सारः उपयोगः एवhashmapकार्यान्वितम् अस्ति, अतः नक्शा मूलतः अस्ति哈希表

哈希表इति प्रयोगः哈希函数दत्तांशं दत्तांशसंरचनेषु व्यवस्थितं कुर्वन्तु ये द्रुतप्रवेशं अन्वेषणं च समर्थयन्ति।

哈希函数 , यत् हैश फंक्शन् इति अपि ज्ञायते, तत् एकं फंक्शन् अस्ति यत् विशिष्टस्य हैश एल्गोरिदम् इत्यस्य माध्यमेन कस्यापि दीर्घतायाः (यथा स्ट्रिंग्) निवेशं नियत-दीर्घतायाः आउटपुट् मध्ये परिवर्तयति हैशमूल्यानां अभिगमनप्रदर्शनं सुनिश्चित्य प्रायः हैशमूल्यानि सरणीरूपे संगृह्यन्ते ।

यदि निवेशस्य परिधिः नक्शाङ्कितस्य निर्गमस्य परिधिं अतिक्रमति तर्हि भिन्न-भिन्न-निवेशानां समानं निर्गमं प्राप्तुं शक्नोति哈希冲突

प्रायः एतस्याः समस्यायाः समाधानार्थं द्वौ उपायौ स्तः ।开放地址法तथा拉链法

(1) नक्शा कार्यान्वयन योजना

मुक्तसङ्केतविधिः : १.

दत्तांशसंरचनानि प्रायः सरणीनां उपयोगेन कार्यान्विताः भवन्ति

  • 1. प्रथमं, सरणी भिन्न-भिन्न-हैश-मूल्यानां कृते निर्मितं भवति, यत् हैश-सारणी इति कथ्यते ।
  • 2. ततः अनेकाः कीलानि निर्वहन्तु तथा च पतां तत्सम्बद्धस्थाने स्थापितं इति पुष्टिं कर्तुं हैशकार्यं कुर्वन्तु यदि हैशसारणीयाः एषः स्लॉट् पूर्वमेव कब्जाकृतः अस्ति तर्हि अन्वेषणक्रमस्य उपयोगं कुर्वन्तु (यथा रेखीयपरिचयः, गौणपरिचयः अथवा द्विगुणहैशिंग् , इत्यादीनि) अग्रिम-कुञ्जीम् अन्वेष्टुं तथा च तत्र परस्परविरोधिनः कीलानि संग्रहीतुं शक्नुवन्ति ।

अभावः : १.

अस्मिन् उपाये विग्रहाणां समाधानार्थं अधिकं स्थानस्य आवश्यकता भवति यतोहि न केवलं दत्तांशः संगृहीतः भवति, अपितु टकरावस्य समाधानार्थं अतिरिक्तस्थानं आवश्यकं भवति ।

जिपर-विधिः (go language map इत्यनेन एषा पद्धतिः उपयुज्यते):

सरणीः, लिङ्क्ड् सूचीः च प्रायः अन्तर्निहितदत्तांशसंरचनारूपेण उपयुज्यन्ते

  • 1. सर्वप्रथमं, सरणी भिन्न-भिन्न-हैश-मूल्यानां कृते निर्मितं भवति, यत् हैश-सारणीम् इति कथ्यते ।
  • 2. ततः बहवः कीलानि आगमिष्यन्ति भिन्न-भिन्न-कील-हैश-करणानन्तरं हैश-मूल्यं मॉड्यूल्-रूपेण गणितं भवति तथा च समान-हैश-मूल्येन (हैश-टकराव) सन्दर्भे नूतनं कीलं विद्यमान-कुंजी-सूचौ लम्बितम् भविष्यति । कालान्तरे
  • 3. यदा भवन्तः विशिष्टं कुञ्जीम् अन्वेष्टुम् इच्छन्ति तदा प्रथमं तस्य स्थानं निर्धारयितुं हैश फंक्शन् इत्यस्य उपयोगं कुर्वन्तु, ततः तस्मिन् स्थाने लिङ्क् कृते सूचीयां रेखीय अन्वेषणं कुर्वन्तु यावत् भवन्तः मेलनं कुञ्जीम् न प्राप्नुवन्ति अथवा लिङ्क् कृतस्य सूचीयाः अन्ते न प्राप्नुवन्ति

सरणीयाः विभिन्नेषु अनुक्रमणिकासु लिङ्क् कृतं लिङ्क् कृतं सूचीं बकेट् इति अपि उच्यते ।

(2) मानचित्रस्य अन्तर्निहितसंरचना

ह्मप
type hmap struct {
 count     int // 当前哈希表中的元素数量,即键值对数量,可用内置函数len()获取
 flags     uint8  // 标志位,标记map状态和属性的字段,如正在迭代等状态
 B         uint8  // 表示哈希表桶(buckets)的数量为2的B次方
 noverflow uint16 // 溢出桶的大致数量,扩容时会用到
 hash0     uint32 // 哈希种子,对key做哈希是加入种子计算哈希值,确保map安全性

 buckets    unsafe.Pointer // 存储桶数组的指针
 oldbuckets unsafe.Pointer // 扩容时用于保存旧桶数组的指针 , 大小为新桶数组的一半
 nevacuate  uintptr        // 扩容时的迁移进度器,迁移桶下标小于此值说明完成迁移

 extra *mapextra // 溢出桶的指针,指向mapextra结构体,用于存储一些额外的字段和信息
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
// mapextra 处理桶溢出的结构体
type mapextra struct {
 overflow    *[]*bmap    // 溢出桶数组指针,仅当key和elem非指针时才使用
 oldoverflow *[]*bmap    // 旧的溢出桶数组指针,仅当key和elem非指针时才使用

 nextOverflow *bmap      // 下一个可用的溢出桶地址
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
bmap

स्रोतसङ्केते bmap प्रकारस्य केवलं एकं tophash क्षेत्रं भवति ।परन्तु संकलनस्य समये Go संकलकः स्वयमेव उपयोक्तृसङ्केतस्य अनुसारं तत्सम्बद्धान् कीलम्, मूल्यम् अन्यसंरचनानि च इन्जेक्ट् करिष्यति ।

पृष्ठीय bmap

type bmap struct {
	// tophash generally contains the top byte of the hash value
	// for each key in this bucket. If tophash[0] < minTopHash,
	// tophash[0] is a bucket evacuation state instead.
	tophash [bucketCnt]uint8
	// Followed by bucketCnt keys and then bucketCnt elems.
	// NOTE: packing all the keys together and then all the elems together makes the
	// code a bit more complicated than alternating key/elem/key/elem/... but it allows
	// us to eliminate padding which would be needed for, e.g., map[int64]int8.
	// Followed by an overflow pointer.
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

वास्तविक bmap

// 编译期间会动态地创建一个新的结构:
type bmap struct {
   topbits  [8]uint8   // 这里存储哈希值的高八位,用于在确定key的时候快速试错,加快增删改查寻址效率,有时候也叫tophash
   keys     [8]keytype   // 存储key的数组,这里bmap最多存储8个键值对
   elems   [8]valuetype    // 存储value的数组,这里bmap也最多存储8个键值对
   ...
   overflow uintptr     // 溢出桶指针
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
नक्शा अन्तर्निहित आरेख

अत्र चित्रविवरणं सम्मिलितं कुर्वन्तु

मानचित्रस्य विस्तारः

Go भाषायां नक्शाप्रदर्शनं निर्वाहयितुम् स्वयमेव नक्शाविस्तारः क्रियते ।

प्रथमं लेखनकाले नक्शा उत्तीर्णः भवतिruntime.mapassignविस्तारस्य आवश्यकता अस्ति वा इति निर्धारयन्तु

func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
...
 // If we hit the max load factor or we have too many overflow buckets,
 // and we're not already in the middle of growing, start growing.
 if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
  hashGrow(t, h)
  goto again // Growing the table invalidates everything, so try again
 }
...
}

// overLoadFactor reports whether count items placed in 1<<B buckets is over loadFactor.
func overLoadFactor(count int, B uint8) bool {
 return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen)
}

func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
 if B > 15 {
  B = 15
 }
 return noverflow >= uint16(1)<<(B&15)
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

उपर्युक्तसंहितानुसारं विस्तारस्य न्यायार्थं द्वौ शर्तौ स्तः- १.

  • भारगुणकः सीमां 6.5 अतिक्रमति:overLoadFactor(h.count+1, h.B) , भारगुणकः = तत्त्वानां संख्या ÷ बाल्टीनां संख्या
  • अत्यधिकाः ओवरफ्लो बाल्टीः प्रयुक्ताः (३२७६८ अतिक्रान्ताः):tooManyOverflowBuckets(h.noverflow, h.B))

विस्तारविधिः : १.

  • वृद्धिशीलविस्तारः : १.

यदा भारकारकः अतिबृहत् भवति तदा नूतनं लोटादीर्घता मूलदीर्घतायाः द्विगुणं भवति, ततः पुरातनं बाल्टीदत्तांशं नूतनबाल्टीं प्रति स्थानान्तरितम् अस्ति ।

  • समानक्षमताविस्तारः

तत्र बहु ​​दत्तांशः नास्ति, परन्तु अतिप्रवाहलोटाः सन्ति ।विस्तारस्य समये, बाल्टीनां संख्या अपरिवर्तिता एव तिष्ठति, वृद्धिशीलविस्तारसदृशानि स्थानान्तरणक्रियाः पुनः क्रियन्ते, तथा च बाल्टी-उपयोगं वर्धयितुं द्रुततरं प्रवेशं सुनिश्चित्य शिथिल-की-मूल्ययुग्मानि पुनः व्यवस्थितानि भवन्ति

विस्तारपदार्थाः : १.

  • 1. नवीनं बाल्टी सरणी:मूलप्रमाणेन सह नूतनं रचयन्तुद्विद्वारनूतनं bucket array विस्तारितं इति चिह्नितं भविष्यति ।
func hashGrow(t *maptype, h *hmap) {
 ...
 // 原有桶设置给oldbuckets
 oldbuckets := h.buckets   
 // 创建新桶
 newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger, nil)

 flags := h.flags &^ (iterator | oldIterator)
 if h.flags&iterator != 0 {
  flags |= oldIterator
 }
 // commit the grow (atomic wrt gc)
 h.B += bigger
 h.flags = flags
 h.oldbuckets = oldbuckets
 h.buckets = newbuckets
 h.nevacuate = 0
 h.noverflow = 0

 ...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 2. रेहशः: मूलबाल्टी-सरणीं प्रति सूचयितुं oldbuckets इत्यस्य उपयोगं कुर्वन्तु, नूतनं bucket array -इत्येतत् दर्शयितुं buckets इत्यस्य उपयोगं कुर्वन्तु, पुरातन-bucket array इत्यस्मिन् सर्वाणि कील-मूल्ययुग्मानि भ्रमन्तु, तथा च प्रत्येकस्य कीलस्य स्थितिं पुनः गणयितुं नूतने सम्मिलितुं च hash function इत्यस्य उपयोगं कुर्वन्तु बाल्टी सरणी ।
// 这个是mapdelete函数中的处理迁移的位置
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
...
 if h.growing() {
  // 
  growWork(t, h, bucket)
 }
...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 3. क्रमिकप्रवासः: विस्तारस्य समये सम्पूर्णं कार्यक्रमं विरामं न कर्तुं Go's Map कार्यान्वयनम् चयनं कर्तुं शक्नोति渐进式驱逐 कील-मूल्ययुग्मानि प्रवासयन्तु। अस्य अर्थः अस्ति यत् विस्तारस्य समये पुरातनः बाल्टी-सरणयः नूतनः बाल्टी-सरणयः च एकस्मिन् समये विद्यन्ते, नवनिवेशितानि कील-मूल्ययुग्मानि प्रत्यक्षतया नूतन-बाल्टी-मध्ये स्थापितानि भविष्यन्ति, पुरातन-बाल्टी-सरणौ प्रवासन-क्रियाम् आरभते
// 进入后是一个简单的判断,之后的evacuate是核心逻辑处理,特别多,感兴趣自己看源码
func growWork(t *maptype, h *hmap, bucket uintptr) {
	// make sure we evacuate the oldbucket corresponding
	// to the bucket we're about to use
	evacuate(t, h, bucket&h.oldbucketmask())

	// evacuate one more oldbucket to make progress on growing
	if h.growing() {
		evacuate(t, h, h.nevacuate)
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 4. आन्तरिकस्थितिं अद्यतनं कुर्वन्तु: यदा oldbuckets मध्ये सर्वाणि key-value युग्मानि स्थानान्तरितानि भवन्ति तदा Map इत्यस्य आन्तरिकस्थितिः अद्यतनं भविष्यति तथा च oldbuckets विलोपनं भविष्यति ।

4.उपयोगपरिदृश्यानि

  • 1.शीघ्रं अन्वेषणम्: यदा भवन्तः शीघ्रं कुञ्जिकायाः ​​आधारेण मूल्यं पश्यितुं प्रवृत्ताः भवन्ति तदा Map O(1) इत्यस्य औसतसमयजटिलतायाः सह लुकअप-प्रदर्शनं प्रदाति ।
  • 2.डुप्लिकेट् निष्कासयन्तु: यदा अद्वितीयकुञ्जीनां संग्रहणस्य आवश्यकता भवति तदा Map कीलानां पुनरावृत्तिः न भवति, तथा च द्विगुणीकरणकार्यं स्वाभाविकतया प्राप्तुं शक्यते ।
  • 3.गतिशील संग्रह: नक्शा लचीलाः कार्याणि प्रदाति यदा कील-मूल्ययुग्मानि गतिशीलरूपेण योजयितुं वा विलोपयितुं वा आवश्यकाः भवन्ति ।
  • 4.लिङ्क्ड् डाटा: नक्शा तदा उत्तमः विकल्पः भवति यदा दत्तांशः कुञ्जी-मूल्ययुग्मरूपेण विद्यते तथा च अद्यतनीकरणस्य अथवा बहुधा प्रश्नस्य आवश्यकता भवति ।

5. उपयोगस्य सुझावः

  1. पूर्व आवंटित: ज्ञाताकारस्य मानचित्रे क्षमता आवंटयितुं make फंक्शन् इत्यस्य उपयोगं कर्तुं प्रयतध्वम् ।
  2. दत्तांशप्रकारचयनम्: बृहत्तरदत्तांशप्रकारस्य उपयोगं कुर्वन्तु, यथाintवाint64
  3. सूचकभण्डारणम्: बृहत् परिमाणेन दत्तांशयुक्तानां संरचनानां वा चरानाम् कृते मूल्यानां स्थानान्तरणाय, संग्रहणाय च सूचकानाम् उपयोगं कर्तुं प्रयतध्वम् ।
  4. समवर्ती नियन्त्रण: समवर्तीप्रवेशार्थं, उपयोगं कुर्वन्तुsync.Mapअथवा स्वस्य समवर्ती सुरक्षितं मानचित्रं कार्यान्वयन्तु।

6.सन्दर्भसामग्री