در این قسمت به بررسی مواردی مهم از ساختمان داده در زبان گو میپردازیم و این آموزش مناسب افرادی هست که با مباحث ساختمان داده آشنایی داشته باشند.
10.1.1 Queue in Golang #
یک صف (queue) ساده را می توان با استفاده از GO به کمک موارد زیر پیاده سازی کرد:
- container/list package
- slice
یک صف عملیات زیر را انجام میدهد:
- Enqueue
- Dequeue
- Front
- Size
- Empty
10.1.1.1 List Implementation #
پیاده سازی صف به کمک لیستها
1package main
2
3import (
4 "container/list"
5 "fmt"
6)
7
8type customQueue struct {
9 queue *list.List
10}
11
12func (c *customQueue) Enqueue(value string) {
13 c.queue.PushBack(value)
14}
15
16func (c *customQueue) Dequeue() error {
17 if c.queue.Len() > 0 {
18 ele := c.queue.Front()
19 c.queue.Remove(ele)
20 }
21 return fmt.Errorf("Pop Error: Queue is empty")
22}
23
24func (c *customQueue) Front() (string, error) {
25 if c.queue.Len() > 0 {
26 if val, ok := c.queue.Front().Value.(string); ok {
27 return val, nil
28 }
29 return "", fmt.Errorf("Peep Error: Queue Datatype is incorrect")
30 }
31 return "", fmt.Errorf("Peep Error: Queue is empty")
32}
33
34func (c *customQueue) Size() int {
35 return c.queue.Len()
36}
37
38func (c *customQueue) Empty() bool {
39 return c.queue.Len() == 0
40}
41
42func main() {
43 customQueue := &customQueue{
44 queue: list.New(),
45 }
46 fmt.Printf("Enqueue: A\n")
47 customQueue.Enqueue("A")
48 fmt.Printf("Enqueue: B\n")
49 customQueue.Enqueue("B")
50 fmt.Printf("Size: %d\n", customQueue.Size())
51 for customQueue.Size() > 0 {
52 frontVal, _ := customQueue.Front()
53 fmt.Printf("Front: %s\n", frontVal)
54 fmt.Printf("Dequeue: %s\n", frontVal)
55 customQueue.Dequeue()
56 }
57 fmt.Printf("Size: %d\n", customQueue.Size())
58}
خروجی برنامه بالا:
10.1.1.2 Slice Implementation #
پیاده سازی صف به کمک slice
1package main
2
3import (
4 "fmt"
5 "sync"
6)
7
8type customQueue struct {
9 queue []string
10 lock sync.RWMutex
11}
12
13func (c *customQueue) Enqueue(name string) {
14 c.lock.Lock()
15 defer c.lock.Unlock()
16 c.queue = append(c.queue, name)
17}
18
19func (c *customQueue) Dequeue() error {
20 if len(c.queue) > 0 {
21 c.lock.Lock()
22 defer c.lock.Unlock()
23 c.queue = c.queue[1:]
24 return nil
25 }
26 return fmt.Errorf("Pop Error: Queue is empty")
27}
28
29func (c *customQueue) Front() (string, error) {
30 if len(c.queue) > 0 {
31 c.lock.Lock()
32 defer c.lock.Unlock()
33 return c.queue[0], nil
34 }
35 return "", fmt.Errorf("Peep Error: Queue is empty")
36}
37
38func (c *customQueue) Size() int {
39 return len(c.queue)
40}
41
42func (c *customQueue) Empty() bool {
43 return len(c.queue) == 0
44}
45
46func main() {
47 customQueue := &customQueue{
48 queue: make([]string, 0),
49 }
50
51 fmt.Printf("Enqueue: A\n")
52 customQueue.Enqueue("A")
53 fmt.Printf("Enqueue: B\n")
54 customQueue.Enqueue("B")
55 fmt.Printf("Len: %d\n", customQueue.Size())
56
57 for customQueue.Size() > 0 {
58 frontVal, _ := customQueue.Front()
59 fmt.Printf("Front: %s\n", frontVal)
60 fmt.Printf("Dequeue: %s\n", frontVal)
61 customQueue.Dequeue()
62 }
63 fmt.Printf("Len: %d\n", customQueue.Size())
64}
خروجی برنامه بالا:
Enqueue: A
Enqueue: B
Size: 2
Front: A
Dequeue: A
Front: B
Dequeue: B
Size: 0
10.1.2 Stack in Golang #
یک پشته (Stack) ساده را می توان با استفاده از GO به کمک موارد زیر پیاده سازی کرد:
- container/list package
- slice
یک stack عملیات زیر را انجام میدهد:
- Push
- Pop
- Front
- Size
- Empty
10.1.2.1 List Implementation #
پیاده سازی پشته به کمک لیستها
1package main
2
3import (
4 "container/list"
5 "fmt"
6)
7
8type customStack struct {
9 stack *list.List
10}
11
12func (c *customStack) Push(value string) {
13 c.stack.PushFront(value)
14}
15
16func (c *customStack) Pop() error {
17 if c.stack.Len() > 0 {
18 ele := c.stack.Front()
19 c.stack.Remove(ele)
20 }
21 return fmt.Errorf("Pop Error: Stack is empty")
22}
23
24func (c *customStack) Front() (string, error) {
25 if c.stack.Len() > 0 {
26 if val, ok := c.stack.Front().Value.(string); ok {
27 return val, nil
28 }
29 return "", fmt.Errorf("Peep Error: Stack Datatype is incorrect")
30 }
31 return "", fmt.Errorf("Peep Error: Stack is empty")
32}
33
34func (c *customStack) Size() int {
35 return c.stack.Len()
36}
37
38func (c *customStack) Empty() bool {
39 return c.stack.Len() == 0
40}
41
42func main() {
43 customStack := &customStack{
44 stack: list.New(),
45 }
46 fmt.Printf("Push: A\n")
47 customStack.Push("A")
48 fmt.Printf("Push: B\n")
49 customStack.Push("B")
50 fmt.Printf("Size: %d\n", customStack.Size())
51 for customStack.Size() > 0 {
52 frontVal, _ := customStack.Front()
53 fmt.Printf("Front: %s\n", frontVal)
54 fmt.Printf("Pop: %s\n", frontVal)
55 customStack.Pop()
56 }
57 fmt.Printf("Size: %d\n", customStack.Size())
58}
خروجی برنامه بالا:
10.1.2.2 Slice Implementation #
پیاده سازی پشته به کمک slice
1package main
2
3import (
4 "fmt"
5 "sync"
6)
7
8type customStack struct {
9 stack []string
10 lock sync.RWMutex
11}
12
13func (c *customStack) Push(name string) {
14 c.lock.Lock()
15 defer c.lock.Unlock()
16 c.stack = append(c.stack, name)
17}
18
19func (c *customStack) Pop() error {
20 len := len(c.stack)
21 if len > 0 {
22 c.lock.Lock()
23 defer c.lock.Unlock()
24 c.stack = c.stack[:len-1]
25 return nil
26 }
27 return fmt.Errorf("Pop Error: Stack is empty")
28}
29
30func (c *customStack) Front() (string, error) {
31 len := len(c.stack)
32 if len > 0 {
33 c.lock.Lock()
34 defer c.lock.Unlock()
35 return c.stack[len-1], nil
36 }
37 return "", fmt.Errorf("Peep Error: Stack is empty")
38}
39
40func (c *customStack) Size() int {
41 return len(c.stack)
42}
43
44func (c *customStack) Empty() bool {
45 return len(c.stack) == 0
46}
47
48func main() {
49 customStack := &customStack{
50 stack: make([]string, 0),
51 }
52 fmt.Printf("Push: A\n")
53 customStack.Push("A")
54 fmt.Printf("Push: B\n")
55 customStack.Push("B")
56 fmt.Printf("Size: %d\n", customStack.Size())
57 for customStack.Size() > 0 {
58 frontVal, _ := customStack.Front()
59 fmt.Printf("Front: %s\n", frontVal)
60 fmt.Printf("Pop: %s\n", frontVal)
61 customStack.Pop()
62 }
63 fmt.Printf("Size: %d\n", customStack.Size())
64}
خروجی برنامه بالا:
10.1.3 Set implementation in Golang #
مجموعه (set) یک ساختار داده ای است که عناصر را بدون نظم خاصی در خود نگه می دارد. یک عنصر فقط یک بار در یک مجموعه ظاهر می شود.
Set را می توان با استفاده از map در GO پیاده سازی کرد. ما از map[string]struct{} برای مجموعه استفاده خواهیم کرد زیرا struct{} هیچ حافظه ای اشغال نمی کند، بنابراین از نظر ذخیره سازی کارآمدتر است.
در زیر مثال ساده مجموعه (set) که دارای عملیات زیر است را داریم:
- Add
- Remove
- Exists
1package main
2
3import (
4 "fmt"
5)
6
7//MakeSet initialize the set
8func makeSet() *customSet {
9 return &customSet{
10 container: make(map[string]struct{}),
11 }
12}
13
14type customSet struct {
15 container map[string]struct{}
16}
17
18func (c *customSet) Exists(key string) bool {
19 _, exists := c.container[key]
20 return exists
21}
22
23func (c *customSet) Add(key string) {
24 c.container[key] = struct{}{}
25}
26
27func (c *customSet) Remove(key string) error {
28 _, exists := c.container[key]
29 if !exists {
30 return fmt.Errorf("Remove Error: Item doesn't exist in set")
31 }
32 delete(c.container, key)
33 return nil
34}
35
36func (c *customSet) Size() int {
37 return len(c.container)
38}
39
40func main() {
41 customSet := makeSet()
42 fmt.Printf("Add: B\n")
43 customSet.Add("A")
44 fmt.Printf("Add: B\n")
45 customSet.Add("B")
46 fmt.Printf("Size: %d\n", customSet.Size())
47 fmt.Printf("A Exists?: %t\n", customSet.Exists("A"))
48 fmt.Printf("B Exists?: %t\n", customSet.Exists("B"))
49 fmt.Printf("C Exists?: %t\n", customSet.Exists("C"))
50 fmt.Printf("Remove: B\n")
51 customSet.Remove("B")
52 fmt.Printf("B Exists?: %t\n", customSet.Exists("B"))
53}
خروجی برنامه بالا:
1Add: B
2Add: B
3Size: 2
4A Exists?: true
5B Exists?: true
6C Exists?: false
7Remove: B
8B Exists?: false
10.1.4 Linked List in Golang #
لیست منفرد یک نوع ساده از لیست پیوندی است که امکان پیمایش در یک جهت یعنی جلو را فراهم می کند. هر گره در لیست پیوندی شامل بخش داده و اشاره گر به گره بعدی در لیست پیوند شده است.
لیست پیوندی اجرا شده در مثال زیر از عملیات زیر پشتیبانی می کند.
- AddFront
- AddBack
- RemoveFront
- RemoveBack
- Traverse
- Front
- Size
1package main
2
3import "fmt"
4
5type ele struct {
6 name string
7 next *ele
8}
9
10type singleList struct {
11 len int
12 head *ele
13}
14
15func initList() *singleList {
16 return &singleList{}
17}
18
19func (s *singleList) AddFront(name string) {
20 ele := &ele{
21 name: name,
22 }
23 if s.head == nil {
24 s.head = ele
25 } else {
26 ele.next = s.head
27 s.head = ele
28 }
29 s.len++
30 return
31}
32
33func (s *singleList) AddBack(name string) {
34 ele := &ele{
35 name: name,
36 }
37 if s.head == nil {
38 s.head = ele
39 } else {
40 current := s.head
41 for current.next != nil {
42 current = current.next
43 }
44 current.next = ele
45 }
46 s.len++
47 return
48}
49
50func (s *singleList) RemoveFront() error {
51 if s.head == nil {
52 return fmt.Errorf("List is empty")
53 }
54 s.head = s.head.next
55 s.len--
56 return nil
57}
58
59func (s *singleList) RemoveBack() error {
60 if s.head == nil {
61 return fmt.Errorf("removeBack: List is empty")
62 }
63 var prev *ele
64 current := s.head
65 for current.next != nil {
66 prev = current
67 current = current.next
68 }
69 if prev != nil {
70 prev.next = nil
71 } else {
72 s.head = nil
73 }
74 s.len--
75 return nil
76}
77
78func (s *singleList) Front() (string, error) {
79 if s.head == nil {
80 return "", fmt.Errorf("Single List is empty")
81 }
82 return s.head.name, nil
83}
84
85func (s *singleList) Size() int {
86 return s.len
87}
88
89func (s *singleList) Traverse() error {
90 if s.head == nil {
91 return fmt.Errorf("TranverseError: List is empty")
92 }
93 current := s.head
94 for current != nil {
95 fmt.Println(current.name)
96 current = current.next
97 }
98 return nil
99}
100
101func main() {
102 singleList := initList()
103 fmt.Printf("AddFront: A\n")
104 singleList.AddFront("A")
105 fmt.Printf("AddFront: B\n")
106 singleList.AddFront("B")
107 fmt.Printf("AddBack: C\n")
108 singleList.AddBack("C")
109
110 fmt.Printf("Size: %d\n", singleList.Size())
111
112 err := singleList.Traverse()
113 if err != nil {
114 fmt.Println(err.Error())
115 }
116
117 fmt.Printf("RemoveFront\n")
118 err = singleList.RemoveFront()
119 if err != nil {
120 fmt.Printf("RemoveFront Error: %s\n", err.Error())
121 }
122
123 fmt.Printf("RemoveBack\n")
124 err = singleList.RemoveBack()
125 if err != nil {
126 fmt.Printf("RemoveBack Error: %s\n", err.Error())
127 }
128
129 fmt.Printf("RemoveBack\n")
130 err = singleList.RemoveBack()
131 if err != nil {
132 fmt.Printf("RemoveBack Error: %s\n", err.Error())
133 }
134
135 fmt.Printf("RemoveBack\n")
136 err = singleList.RemoveBack()
137 if err != nil {
138 fmt.Printf("RemoveBack Error: %s\n", err.Error())
139 }
140
141 err = singleList.Traverse()
142 if err != nil {
143 fmt.Println(err.Error())
144 }
145
146 fmt.Printf("Size: %d\n", singleList.Size())
147}
خروجی برنامه بالا:
1AddFront: A
2AddFront: B
3AddBack: C
4Size: 3
5B
6A
7C
8RemoveFront
9RemoveBack
10RemoveBack
11RemoveBack
12RemoveBack Error: removeBack: List is empty
13TranverseError: List is empty
14Size: 0
10.1.5 Doubly Linked List in Go #
یک لیست مضاعف (Doubly Linked) شامل سه قسمت در گره خود است.
- فیلد داده.
- یک اشاره گر بعدی به گره بعدی در لیست اشاره می کند.
- یک اشاره گر قبلی که به گره قبلی در لیست اشاره می کند.
در اینجا فیلدهای «دادهها» و «بعدی» مانند لیستهای پیوندی منفرد هستند. فیلد اشاره گر «قبلی» ویژگی جدیدی است که لیست پیوندی را به لیست پیوندی دوگانه تبدیل می کند.
در زیر نمونه ای از یک لیست با پیوند دوگانه آورده شده است. اشاره گر قبلی گره head (start) به Null اشاره می کند. به طور مشابه، اشاره گر Next آخرین گره به Null اشاره می کند.
برای پیادهسازی یک doubly linked list در زبان Go، یک ساختار گره با دادهها، اشارهگر قبلی و اشارهگر بعدی، روشهایی برای افزودن گرهها در doubly linked list (از قسمت جلویی یا از انتهای هر دو) و روشهایی برای پیمایش به جلو/عقب ایجاد کنید.
1package main
2
3import "fmt"
4
5type node struct {
6 data string
7 prev *node
8 next *node
9}
10
11type doublyLinkedList struct {
12 len int
13 tail *node
14 head *node
15}
16
17func initDoublyList() *doublyLinkedList {
18 return &doublyLinkedList{}
19}
20
21func (d *doublyLinkedList) AddFrontNodeDLL(data string) {
22 newNode := &node{
23 data: data,
24 }
25 if d.head == nil {
26 d.head = newNode
27 d.tail = newNode
28 } else {
29 newNode.next = d.head
30 d.head.prev = newNode
31 d.head = newNode
32 }
33 d.len++
34 return
35}
36
37func (d *doublyLinkedList) AddEndNodeDLL(data string) {
38 newNode := &node{
39 data: data,
40 }
41 if d.head == nil {
42 d.head = newNode
43 d.tail = newNode
44 } else {
45 currentNode := d.head
46 for currentNode.next != nil {
47 currentNode = currentNode.next
48 }
49 newNode.prev = currentNode
50 currentNode.next = newNode
51 d.tail = newNode
52 }
53 d.len++
54 return
55}
56func (d *doublyLinkedList) TraverseForward() error {
57 if d.head == nil {
58 return fmt.Errorf("TraverseError: List is empty")
59 }
60 temp := d.head
61 for temp != nil {
62 fmt.Printf("value = %v, prev = %v, next = %v\n", temp.data, temp.prev, temp.next)
63 temp = temp.next
64 }
65 fmt.Println()
66 return nil
67}
68
69func (d *doublyLinkedList) TraverseReverse() error {
70 if d.head == nil {
71 return fmt.Errorf("TraverseError: List is empty")
72 }
73 temp := d.tail
74 for temp != nil {
75 fmt.Printf("value = %v, prev = %v, next = %v\n", temp.data, temp.prev, temp.next)
76 temp = temp.prev
77 }
78 fmt.Println()
79 return nil
80}
81
82func (d *doublyLinkedList) Size() int {
83 return d.len
84}
85func main() {
86 doublyList := initDoublyList()
87 fmt.Printf("Add Front Node: C\n")
88 doublyList.AddFrontNodeDLL("C")
89 fmt.Printf("Add Front Node: B\n")
90 doublyList.AddFrontNodeDLL("B")
91 fmt.Printf("Add Front Node: A\n")
92 doublyList.AddFrontNodeDLL("A")
93 fmt.Printf("Add End Node: D\n")
94 doublyList.AddEndNodeDLL("D")
95 fmt.Printf("Add End Node: E\n")
96 doublyList.AddEndNodeDLL("E")
97
98 fmt.Printf("Size of doubly linked ist: %d\n", doublyList.Size())
99
100 err := doublyList.TraverseForward()
101 if err != nil {
102 fmt.Println(err.Error())
103 }
104
105 err = doublyList.TraverseReverse()
106 if err != nil {
107 fmt.Println(err.Error())
108 }
109}
خروجی مورد انتظار برابر حالت زیر است:
1Add Front Node: C
2Add Front Node: B
3Add Front Node: A
4Add End Node: D
5Add End Node: E
6Size of doubly linked ist: 5
7value = A, prev = , next = &{B 0xc000070060 0xc000070020}
8value = B, prev = &{A 0xc000070040}, next = &{C 0xc000070040 0xc000070080}
9value = C, prev = &{B 0xc000070060 0xc000070020}, next = &{D 0xc000070020 0xc0000700a0}
10value = D, prev = &{C 0xc000070040 0xc000070080}, next = &{E 0xc000070080 }
11value = E, prev = &{D 0xc000070020 0xc0000700a0}, next =
12
13value = E, prev = &{D 0xc000070020 0xc0000700a0}, next =
14value = D, prev = &{C 0xc000070040 0xc000070080}, next = &{E 0xc000070080 }
15value = C, prev = &{B 0xc000070060 0xc000070020}, next = &{D 0xc000070020 0xc0000700a0}
16value = B, prev = &{A 0xc000070040}, next = &{C 0xc000070040 0xc000070080}
17value = A, prev = , next = &{B 0xc000070060 0xc000070020}
10.1.6 Tree in Go #
درخت به عنوان یک ساختمان داده غیرخطی تعریف میشود که از مجموعهای از گرهها تشکیل شده است، و این گرهها توسط یالها به یکدیگر متصل شدهاند
خواص یک درخت:
- درخت از یک گره ریشه و صفر یا چند درخت فرعی متصل به آن تشکیل شده است
- گره ریشه بالاترین گره درخت است
- گرههای برگ گرههایی هستند که هیچ فرزندی ندارند
- عمق یک گره تعداد یالها بین ریشه و خودش است
- ارتفاع یک گره تعداد یالها بین خودش و دورترین گره برگ در زیردرخت خود است
1package main
2
3import "fmt"
4
5// Tree represents a tree structure.
6type Tree struct {
7 root *TreeNode
8}
9
10// TreeNode represents a node in the tree.
11type TreeNode struct {
12 data int
13 children []*TreeNode
14}
15
16// insertTree adds a new node with the given data as the root node of the tree.
17func (tree *Tree) insertTree(data int) {
18 if tree.root == nil {
19 tree.root = &TreeNode{data: data}
20 }
21}
22
23// InsertNode adds a new node with the given data as a child of the specified node.
24func (node *TreeNode) insertNode(data int) *TreeNode {
25 newNode := &TreeNode{data: data}
26 node.children = append(node.children, newNode)
27 return newNode
28}
29
30// deleteTree removes the specified node, starting from the root of the tree.
31func (tree *Tree) deleteFromRoot(nodeToDelete *TreeNode) {
32 if tree.root != nil {
33 tree.root = tree.root.deleteNode(nodeToDelete)
34 }
35}
36
37// deleteNode recursively removes the specified node and its descendants from the current node's children.
38func (node *TreeNode) deleteNode(nodeToDelete *TreeNode) *TreeNode {
39 var updatedChildren []*TreeNode
40 for _, child := range node.children {
41 if child != nodeToDelete {
42 updatedChildren = append(updatedChildren, child.deleteNode(nodeToDelete))
43 }
44}
45
46 node.children = updatedChildren
47 return node
48}
49
50// searchFromRoot searches for a node with the specified data starting from the tree's root.
51func (tree *Tree) searchFromRoot(data int) *TreeNode {
52 if tree.root != nil {
53 node := tree.root.searchFromNode(data)
54 return node
55 }
56
57 return nil
58}
59
60// searchFromNode searches for a node with the specified data starting from the current node.
61func (node *TreeNode) searchFromNode(data int) *TreeNode {
62 if node.data == data {
63 return node
64 }
65 for _, child := range node.children {
66 if foundNode := child.searchFromNode(data); foundNode != nil {
67 return foundNode
68 }
69 }
70
71 return nil
72}
73
74// traverseFromRoot initiates a traversal of the tree starting from the root node.
75func (tree *Tree) traverseFromRoot() {
76 if tree.root != nil {
77 tree.root.traverse()
78 }
79}
80
81// traverse performs a recursive traversal starting from the current node.
82func (node *TreeNode) traverse() {
83 if node == nil {
84 return
85 }
86
87 fmt.Printf("%d ", node.data)
88 for _, child := range node.children {
89 child.traverse()
90 }
91}
92
93func main() {
94 // Creating a Tree instance
95 tree := Tree{}
96
97 // Inserting nodes
98 tree.insertTree(1)
99 tree.root.insertNode(2)
100 node3 := tree.root.insertNode(3)
101 node4 := tree.root.insertNode(4)
102 node3.insertNode(5)
103 node3.insertNode(6)
104 node4.insertNode(7)
105
106 // Traversing and printing nodes
107 fmt.Println("Traverse from root:")
108 tree.root.traverse()
109
110 // Searching for node
111 fmt.Println("\nSearch for node 3:")
112 node := tree.searchFromRoot(3)
113 if node != nil {
114 fmt.Println("node found")
115 } else {
116 fmt.Println("node not found")
117 }
118
119 fmt.Println("Search for node 8:")
120 node8 := tree.searchFromRoot(8)
121 if node8 != nil {
122 fmt.Println("node found")
123 } else {
124 fmt.Println("node not found")
125 }
126
127 // Deleting a node
128 fmt.Println("After deleting node 3:")
129 tree.deleteFromRoot(node3)
130 tree.root.traverse()
131}
خروجی برنامه بالا:
1Traverse from root:
21 2 3 5 6 4 7
3Search for node 3
4node found
5Search for node 8
6node not found
7After deleting node 3:
81 2 4 7
10.1.7 Binary Tree in Go #
درخت دودویی، نوعی ساختار دادهای درخت است که هر گره آن میتواند حداکثر دو فرزند (یک فرزند چپ و یک فرزند راست) داشته باشد
1package main
2
3import "fmt"
4
5// BinaryTree represents a binary tree.
6type BinaryTree struct {
7 root *BinaryNode
8}
9
10// BinaryNode represents a node in the binary tree.
11type BinaryNode struct {
12 data int
13 left *BinaryNode
14 right *BinaryNode
15}
16
17// insertFromRoot inserts a new node with the given data into the tree.
18func (tree *BinaryTree) insertFromRoot(data int) *BinaryTree {
19 if tree.root != nil {
20 tree.root.insertNode(data)
21 } else {
22 tree.root = &BinaryNode{data: data}
23 }
24
25 return tree
26}
27
28// insertNode inserts a new node with the given data into the subtree rooted at the current node using level-order traversal.
29func (node *BinaryNode) insertNode(data int) *BinaryNode {
30 var tempNode *BinaryNode
31 queue := []*BinaryNode{node}
32
33 for len(queue) > 0 {
34 tempNode, queue = queue[0], queue[1:]
35
36 if tempNode.left == nil {
37 tempNode.left = &BinaryNode{data: data}
38 break
39 }
40 queue = append(queue, tempNode.left)
41
42 if tempNode.right == nil {
43 tempNode.right = &BinaryNode{data: data}
44 break
45 }
46 queue = append(queue, tempNode.right)
47 }
48
49 return node
50}
51
52// deleteFromRoot deletes a specific node from the binary tree starting from the root.
53func (tree *BinaryTree) deleteFromRoot(nodeToDelete *BinaryNode) {
54 if tree.root != nil {
55 tree.root.deleteNode(nodeToDelete)
56 }
57}
58
59// deletetNode attempts to delete a specific node from the subtree rooted at the current node.
60func (node *BinaryNode) deleteNode(nodeToDelete *BinaryNode) *BinaryNode {
61 var keyNode, lastNode, tempNode *BinaryNode
62 queue := []*BinaryNode{node}
63
64 for len(queue) > 0 {
65 tempNode, queue = queue[0], queue[1:]
66
67 if tempNode == nodeToDelete {
68 keyNode = tempNode
69 }
70
71 if tempNode.left != nil {
72 lastNode, queue = tempNode, append(queue, tempNode.left)
73 }
74
75 if tempNode.right != nil {
76 lastNode, queue = tempNode, append(queue, tempNode.right)
77 }
78 }
79
80
81
82 if keyNode != nil {
83 keyNode.data = tempNode.data
84
85 if lastNode.right == tempNode {
86 lastNode.right = nil
87 } else {
88 lastNode.left = nil
89 }
90 }
91
92 return node
93}
94
95// searchFromRoot searches for a node with the given data in the binary tree starting from the root.
96func (tree *BinaryTree) searchFromRoot(data int) *BinaryNode {
97 if tree.root != nil {
98 return tree.root.searchFromNode(data)
99 }
100
101 return nil
102}
103
104// searchFromNode performs a level-order traversal to find a node with the given data
105func (node *BinaryNode) searchFromNode(data int) *BinaryNode {
106 var tempNode *BinaryNode
107 queue := []*BinaryNode{node}
108
109 for len(queue) > 0 {
110 tempNode, queue = queue[0], queue[1:]
111
112 if tempNode.data == data {
113 return tempNode
114 }
115
116 if tempNode.left != nil {
117 queue = append(queue, tempNode.left)
118 }
119
120 if tempNode.right != nil {
121 queue = append(queue, tempNode.right)
122 }
123 }
124
125 return nil
126}
127
128// printTreeInOrder prints the values of nodes in the binary tree starting from root using an in-order traversal.
129func (tree *BinaryTree) printTreeInOrder() {
130 if tree.root != nil {
131 tree.root.printSubTreeInOrder()
132 }
133}
134
135// printTreePreOrder prints the values of nodes in the binary tree starting from root using a pre-order traversal.
136func (tree *BinaryTree) printTreePreOrder() {
137 if tree.root != nil {
138 tree.root.printSubTreePreOrder()
139 }
140}
141
142// printTreePostOrder prints the values of nodes in the binary tree starting from root using a post-order traversal.
143func (tree *BinaryTree) printTreePostOrder() {
144 if tree.root != nil {
145 tree.root.printSubTreePostOrder()
146 }
147}
148
149// printSubTreeInOrder prints the values of nodes in the subtree rooted at the given node using an in-order traversal.
150func (node *BinaryNode) printSubTreeInOrder() {
151 if node != nil {
152 node.left.printSubTreeInOrder()
153 fmt.Printf("%d ", node.data)
154 node.right.printSubTreeInOrder()
155 }
156}
157
158// printSubTreePreOrder prints the values of nodes in the subtree rooted at the given node using a pre-order traversal.
159func (node *BinaryNode) printSubTreePreOrder() {
160 if node != nil {
161 fmt.Printf("%d ", node.data)
162 node.left.printSubTreePreOrder()
163 node.right.printSubTreePreOrder()
164 }
165}
166
167// printSubTreePostOrder prints the values of nodes in the subtree rooted at the given node using a post-order traversal.
168func (node *BinaryNode) printSubTreePostOrder() {
169 if node != nil {
170 node.left.printSubTreePostOrder()
171 node.right.printSubTreePostOrder()
172 fmt.Printf("%d ", node.data)
173 }
174}
175
176func main() {
177 // Create a new binary tree
178 tree := BinaryTree{}
179
180 // Insert nodes
181 tree.insertFromRoot(1)
182 tree.insertFromRoot(2)
183 tree.insertFromRoot(3)
184 tree.insertFromRoot(4)
185 tree.insertFromRoot(5)
186 tree.insertFromRoot(6)
187 tree.insertFromRoot(7)
188
189 fmt.Println("In-Order Traversal:")
190 tree.printTreeInOrder()
191
192 fmt.Println("\nPre-Order Traversal:")
193 tree.printTreePreOrder()
194
195 fmt.Println("\nPost-Order Traversal:")
196 tree.printTreePostOrder()
197
198 // Search for a node
199 fmt.Println("\n\nSearching for node with data 6:")
200 nodeToSearch := tree.searchFromRoot(6)
201
202 if nodeToSearch != nil {
203 fmt.Println("found node with data 6:", nodeToSearch.data)
204 } else {
205 fmt.Println("node with data 6 not found.")
206 }
207
208 fmt.Println("\nSearching for node with data 9:")
209 nodeToSearch = tree.searchFromRoot(9)
210
211 if nodeToSearch != nil {
212 fmt.Println("found node with data 9:", nodeToSearch.data)
213 } else {
214 fmt.Println("node with data 9 not found.")
215 }
216
217 fmt.Println("\nDeleting node with data 4:")
218 nodeToDelete := tree.searchFromRoot(4)
219
220 if nodeToDelete != nil {
221 fmt.Println("deleted node with data 4.")
222 tree.deleteFromRoot(nodeToDelete)
223 } else {
224 fmt.Println("node with data 4 not found.")
225 }
226
227 fmt.Println("\nIn-Order Traversal after deletion:")
228 tree.printTreeInOrder()
229}
خروجی کد بالا:
1In-Order Traversal:
24 2 5 1 6 3 7
3Pre-Order Traversal:
41 2 4 5 3 6 7
5Post-Order Traversal:
64 5 2 6 7 3 1
7
8Searching for node with data 6:
9found node with data 6: 6
10
11Searching for node with data 9:
12node with data 9 not found.
13
14Deleting node with data 4:
15deleted node with data 4.
16
17In-Order Traversal after deletion:
187 2 5 1 6 3
10.1.8 Binary Search Tree in Go #
درخت جستجو دودویی یک نوع از درخت دودویی است که ب هر گره دارای یک مقدار داده و دو زیردرخت (زیردرخت چپ و زیردرخت راست) میباشد. در این درخت، دادههای کوچکتر از مقدار دادهٔ گره مورد نظر در زیردرخت چپ قرار میگیرند و دادههای بزرگتر در زیردرخت راست قرار میگیرند . درخت جستجو دودویی به گونه ای طراحی شده است که عملیات جستجو، افزودن و حذف به طور موثر انجام شود
1package main
2
3import "fmt"
4
5// BinarySearchTree represents a binary search tree.
6type BinarySearchTree struct {
7 root *BinarySearchNode
8}
9
10// BinarySearchNode represents a node in the binary search tree.
11type BinarySearchNode struct {
12 data int
13 left *BinarySearchNode
14 right *BinarySearchNode
15}
16
17// insertFromRoot inserts a new node with the given data into the binary search tree, starting from the root of the tree.
18func (tree *BinarySearchTree) insertFromRoot(data int) *BinarySearchTree {
19 if tree.root != nil {
20 tree.root.insertNode(data)
21 } else {
22 tree.root = &BinarySearchNode{data: data}
23 }
24
25 return tree
26}
27
28// insertNode inserts a new node with the given data into the binary search tree rooted at the current node.
29func (node *BinarySearchNode) insertNode(data int) *BinarySearchNode {
30 if node == nil {
31 return &BinarySearchNode{data: data}
32 } else if data == node.data {
33 return node
34 } else if data > node.data {
35 node.right = node.right.insertNode(data)
36 } else {
37 node.left = node.left.insertNode(data)
38 }
39
40 return node
41}
42
43// deleteFromRoot deletes a specific node from the binary search tree starting from the root node.
44func (tree *BinarySearchTree) deleteFromRoot(nodeToDelete *BinarySearchNode) *BinarySearchNode {
45 if tree.root != nil {
46 return tree.root.left.deleteNode(nodeToDelete)
47 }
48
49 return nil
50}
51
52// deleteNode recursively deletes a specific node from the subtree rooted at the current node.
53func (node *BinarySearchNode) deleteNode(nodeToDelete *BinarySearchNode) *BinarySearchNode {
54 if node == nil {
55 return nil
56 }
57
58 if nodeToDelete.data < node.data {
59 node.left = node.left.deleteNode(nodeToDelete)
60 } else if nodeToDelete.data > node.data {
61 node.right = node.right.deleteNode(nodeToDelete)
62 } else {
63
64 if node.left == nil {
65 return node.right
66 } else if node.right == nil {
67 return node.left
68 }
69
70 minNode := node.right.findMin()
71 node.data = minNode.data
72 node.right = node.right.deleteNode(nodeToDelete)
73 }
74
75 return node
76
77}
78
79// findMin returns the minimum node value in the subtree rooted at the current node.
80func (node *BinarySearchNode) findMin() *BinarySearchNode {
81 for node.left != nil {
82 node = node.left
83 }
84
85 return node
86}
87
88// searchFromRoot searches for a node with the specified data in the binary search tree starting from the root node.
89func (tree *BinarySearchTree) searchFromRoot(data int) *BinarySearchNode {
90 if tree.root != nil {
91 return tree.root.searchNode(data)
92 }
93
94 return nil
95}
96
97
98
99// searchNode recursively searches for a node with the specified data in the subtree rooted at the current node.
100func (node *BinarySearchNode) searchNode(data int) *BinarySearchNode {
101 if node == nil {
102 return nil
103 }
104
105 if node.data == data {
106 return node
107 } else if data > node.data {
108 return node.right.searchNode(data)
109 } else if data < node.data {
110 return node.left.searchNode(data)
111 }
112
113 return nil
114}
115
116// printTreeInOrder prints the values of nodes in the binary search tree starting from root using an in-order traversal.
117func (tree *BinarySearchTree) printTreeInOrder() {
118 if tree.root != nil {
119 tree.root.printSubTreeInOrder()
120 }
121}
122
123// printTreePreOrder prints the values of nodes in the binary search tree starting from root using a pre-order traversal.
124
125func (tree *BinarySearchTree) printTreePreOrder() {
126 if tree.root != nil {
127 tree.root.printSubTreePreOrder()
128 }
129}
130
131// printTreePostOrder prints the values of nodes in the binary search tree starting from root using a post-order traversal.
132func (tree *BinarySearchTree) printTreePostOrder() {
133 if tree.root != nil {
134 tree.root.printSubTreePostOrder()
135 }
136}
137
138// printSubTreeInOrder prints the values of nodes in the subtree rooted at the given node using an in-order traversal.
139func (node *BinarySearchNode) printSubTreeInOrder() {
140 if node != nil {
141 node.left.printSubTreeInOrder()
142 fmt.Printf("%d ", node.data)
143 node.right.printSubTreeInOrder()
144 }
145}
146
147// printSubTreePreOrder prints the values of nodes in the subtree rooted at the given node using a pre-order traversal.
148func (node *BinarySearchNode) printSubTreePreOrder() {
149 if node != nil {
150 fmt.Printf("%d ", node.data)
151 node.left.printSubTreePreOrder()
152 node.right.printSubTreePreOrder()
153 }
154}
155
156// printSubTreePostOrder prints the values of nodes in the subtree rooted at the given node using a post-order traversal.
157func (node *BinarySearchNode) printSubTreePostOrder() {
158 if node != nil {
159 node.left.printSubTreePostOrder()
160 node.right.printSubTreePostOrder()
161 fmt.Printf("%d ", node.data)
162 }
163}
164
165func main() {
166
167 // Create a BinarySearchTree
168 bst := &BinarySearchTree{}
169 bst.insertFromRoot(5).insertFromRoot(3).insertFromRoot(7).
170 insertFromRoot(2).insertFromRoot(4)
171
172 fmt.Println("In-order traversal:")
173 bst.printTreeInOrder()
174
175 fmt.Println("\nPre-order traversal:")
176 bst.printTreePreOrder()
177
178 fmt.Println("\nPost-order traversal:")
179 bst.printTreePostOrder()
180
181 // Search for a node
182 fmt.Println("\n Searching for node with data 1")
183 searchNode := bst.searchFromRoot(1)
184 if searchNode != nil {
185 fmt.Printf("Node %d found.\n", searchNode.data)
186 } else {
187 fmt.Println("Node not found.")
188 }
189
190 // Search for a node
191 fmt.Println("Searching for node with data 3")
192 searchNode = bst.searchFromRoot(3)
193 if searchNode != nil {
194 fmt.Printf("Node %d found.\n", searchNode.data)
195 } else {
196 fmt.Println("Node not found.")
197 }
198
199 // Delete a node
200 bst.deleteFromRoot(searchNode)
201 fmt.Println("In-order traversal after deleting 3:")
202 bst.printTreeInOrder()
203}
خروجی کد بالا: