الخوارزميات وهياكل البيانات بلغة Go: دليل عملي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا الخوارزميات وهياكل البيانات مهمة في Go

Go (Golang) هي لغة مترجمة حديثة، تم إنشاؤها في Google للأنظمة عالية الأداء. بساطتها ودعمها المدمج للتوازي يجعلانها مثالية لتطوير backend والتطبيقات السحابية والخدمات المصغرة. ومع ذلك، كما هو الحال في أي لغة أخرى، تعتمد كفاءة كود Go بشكل مباشر على فهم الخوارزميات وهياكل البيانات. بدونها، حتى أسرع لغة يمكن أن تتحول إلى عنق زجاجة.

في هذه المقالة، سنقوم بتحليل هياكل البيانات والخوارزميات الرئيسية التي يجب أن يعرفها كل مطور Go: من المصفوفات إلى البحث الثنائي. سترى أمثلة على الكود، وستعرف كيف تعمل "تحت الغطاء"، وستحصل على نصائح عملية للتحسين.



1. هياكل البيانات الأساسية في Go

توفر Go هياكل بيانات مدمجة، لكن استخدامها الصحيح هو مفتاح الأداء. سننظر في ثلاثة أنواع رئيسية: المصفوفات، الشرائح، وجداول التجزئة.



1.1 المصفوفات والشرائح (Slices)

المصفوفة في Go هي تسلسل ثابت من العناصر من نفس النوع. الشريحة هي غلاف ديناميكي فوق المصفوفة، يسمح بتغيير الحجم.

package main

import "fmt"

func main() { // مصفوفة بطول ثابت var arr [5]int = [5]int{1, 2, 3, 4, 5} fmt.Println("المصفوفة:", arr)

// شريحة - هيكل ديناميكي slice := []int{10, 20, 30} slice = append(slice, 40) // إضافة عنصر fmt.Println("الشريحة:", slice)

// شريحة من مصفوفة subSlice := arr[1:4] // [2, 3, 4] fmt.Println("الشريحة الفرعية:", subSlice)}

نصيحة: استخدم دائمًا الشرائح بدلاً من المصفوفات للمرونة، لكن تذكر أن append قد يتسبب في إعادة توزيع الذاكرة. قم بتعيين السعة مسبقًا باستخدام make([]int, 0, capacity).



1.2 جداول التجزئة (Map)

Map (الخريطة) هي مجموعة غير مرتبة من أزواج المفتاح والقيمة. في Go، يتم تنفيذ map كجدول تجزئة، مما يوفر متوسط وقت وصول O(1).

package main

import "fmt"

func main() { // إنشاء map scores := make(map[string]int) scores["Alice"] = 95 scores["Bob"] = 87

// قراءة مع التحقق if val, ok := scores["Alice"]; ok { fmt.Println("درجة Alice:", val) }

// حذف delete(scores, "Bob") fmt.Println("بعد الحذف:", scores)}

هام: Map لا يدعم الوصول المتزامن بدون مزامنة. للسيناريوهات متعددة الخيوط، استخدم sync.Map أو الأقفال (mutexes).



2. تنفيذ القائمة المرتبطة في Go

القوائم المرتبطة نادرًا ما توجد في Go بسبب وجود الشرائح، لكنها مفيدة لفهم المؤشرات والهياكل الديناميكية. سننظر في قائمة مرتبطة بشكل فردي.



2.1 هيكل العقدة والعمليات الأساسية

package main

import "fmt"

// عقدة القائمةtype Node struct { Value int Next *Node}

// القائمةtype LinkedList struct { Head *Node}

// إضافة في البدايةfunc (ll *LinkedList) Prepend(value int) { newNode := &Node{Value: value, Next: ll.Head} ll.Head = newNode}

// البحث عن عنصرfunc (ll *LinkedList) Search(value int) bool { current := ll.Head for current != nil { if current.Value == value { return true } current = current.Next } return false}

// طباعة القائمةfunc (ll *LinkedList) Print() { current := ll.Head for current != nil { fmt.Printf("%d -> ", current.Value) current = current.Next } fmt.Println("nil")}

func main() { list := LinkedList{} list.Prepend(10) list.Prepend(20) list.Prepend(30) list.Print() // 30 -> 20 -> 10 -> nil fmt.Println("تم العثور على 20:", list.Search(20)) // true}

الأداء: الإدراج في البداية هو O(1)، البحث هو O(n). للوصول المتكرر حسب الفهرس

المدونات

توصيات الكتب