# Stack & queue (go) of data structure and algorithm series

2020-11-09 10:50:11 The following complete code can be obtained from here obtain

## Stack

#### The basic concept of stack

Last in, first out 、 First in, last out is a typical stack structure . Stack can be understood as a restricted linear table , Insertion and deletion can only be done from one end

When a data set only involves inserting and deleting data at one end , And satisfy LIFO 、 Characteristics of first in and second out , Should be the first choice “ Stack ” This data structure （ Browser advances 、 Back function ）

#### The realization of the stack

There are two main operations in a stack , Push and pull , Here, through arrays （ Order of the stack ） And the list （ Chain stack ） There are two ways to implement the stack

##### Order of the stack
``````package arrayStack

import "fmt"

type Item interface {}

type ItemStack struct {
Items []Item
N int
}

//init stack
func (stack *ItemStack) Init() *ItemStack {
stack.Items = []Item{}

return stack
}

//push stack Item
func (stack *ItemStack) Push(item Item) {
if len(stack.Items) > stack.N {
fmt.Println(" The stack is full ")
return
}
stack.Items = append(stack.Items, item)
}

//pop Item from stack
func (stack *ItemStack) Pop() Item {
if len(stack.Items) == 0 {
fmt.Println(" Stack empty ")
return nil
}

item := stack.Items[len(stack.Items) - 1]
stack.Items = stack.Items[0:len(stack.Items) - 1]

return item
}``````
##### Chain stack
``````package linkListStack

import "fmt"

type Item interface {}

type Node struct {
Data Item
Next *Node
}

type Stack struct {
}

//push Stack item
func (stack *Stack) Push(item Item) {
newNode := &Node{Data: item}
}

//pop Item from stack
func (stack *Stack) Pop() Item {
fmt.Println(" Stack empty ")
return nil
}

return item
}

func (stack *Stack) Traverse()  {
fmt.Println(" Stack empty ")
return
}

for currentNode != nil {
fmt.Printf("%v\t", currentNode.Data)
currentNode = currentNode.Next
}
}``````

#### Application scenario of stack

##### Call Stack
The operating system allocates an independent memory space to each thread , This memory is organized into “ Stack ” This structure , It is used to store temporary variables when calling functions . Every time a function is entered , The temporary variable will be put on the stack as a stack frame , When the called function is executed , After returning , Put the stack frame corresponding to this function out of the stack

source ： The beauty of data structure and algorithm

From the execution of this code to understand the function call stack

``````int main() {
int a = 1;
int ret = 0;
int res = 0;
res = a + ret;
printf("%d", res);
reuturn 0;
}

int add(int x, int y) {
int sum = 0;
sum = x + y;
return sum;
}``````

main() The function is called add() function , Get calculation results , And with temporary variables a Add up , Finally print res Value . The program is in progress ,main The variables in the function will be put on the stack successively , When executed add() Function time ,add() The temporary variables in the function will also be put on the stack successively , give the result as follows ： explain ： Stack in memory and data structure stack are not a concept , The stack in memory is a real physical area , The stack in a data structure is an abstract data storage structure

##### The application of stack in expression evaluation

An expression contains two parts , Numbers and operators . We use two stacks to implement expression evaluation , A stack is used to store numbers , A stack is used to store operators

Suppose there is such an expression

``1000+5*6-6``

Traversing the expression from left to right , When it comes to numbers , Put the numbers in the stack where the numbers are stored ; If you encounter an operator , Remove the top element of the storage operator stack , Compare priorities

If it is higher than the top element of the operator stack , The current operator is pushed into the stack where the operator is stored ; If it is lower or the same priority than the top element of the operator stack , Take two elements from the stack where the numbers are stored , Then calculate , Put the result of the calculation into a stack of numbers . Repeat the operation above . Process diagram ： ##### The application of stack in bracket matching

This is also a classic question , It's given a string of parentheses , Verify that it matches exactly , Such as ：

``````{{}   Mismatch
[[{()}]]  matching
([{}]   Mismatch ``````

This can also be solved by stack . Traversing the bracket string from left to right , An unmatched left bracket is pushed onto the stack , When the right bracket is encountered , Take a left bracket from the top of the stack , If it matches , Then continue to traverse the parentheses that follow , When the traversal is finished , The stack is empty , This indicates that the bracket string is a match , Otherwise it doesn't match . The specific implementation is as follows ：

``````package bracketMatch

func BracketsMatch(str string) bool {
brackets := map[rune]rune{')':'(', ']':'[', '}':'['}
var stack []rune

for _, char := range str {
if char == '(' || char == '[' || char == '{' {
stack = append(stack, char)
} else if len(stack) > 0 && brackets[char] == stack[len(stack) - 1] {
stack = stack[:len(stack) - 1]
} else {
return false
}
}

return len(stack) == 0
}
``````

## queue

#### The basic concept of queues

FIFO is a typical queue structure , Queues can also be understood as a limited linear table , Insertion can only be done from the end of the queue , Deletion can only be done from the end of the queue . It's like queuing for tickets

There are only two basic operations of the queue , In and out of the team . The use of queues is really very extensive , Such as message queuing 、 Blocking queues 、 Circular queue, etc

#### Implementation of queues

There are two ways to achieve queues , The sequential queue is realized by array , Through the linked list to realize the chain queue

Two pointers are required to implement the queue , One points to the head of the queue , One points to the end of the queue

##### Sequential queue
``````package arrayQueue

import "fmt"

type Item interface {}

type Queue struct {
Queue []Item
Length int
}

func (queue *Queue) Init() {
queue.Queue = []Item{}
}

func (queue *Queue) Enqueue(data Item) {
if len(queue.Queue) > queue.Length {
fmt.Println(" The queue is full ")
return
}
queue.Queue = append(queue.Queue, data)
}

func (queue *Queue) Dequeue() Item {
if len(queue.Queue) == 0 {
fmt.Println(" The queue is empty ")
return nil
}
item := queue.Queue
queue.Queue = queue.Queue[1:]

return item
}``````
##### Chain queues
``````package linkListQueue

import "fmt"

type Item interface {}

type Node struct {
Data Item
Next *Node
}

type Queue struct {
}

func (queue *Queue) Enqueue(data Item) {
node := &Node{Data: data}
} else {
for currentNode.Next != nil {
currentNode = currentNode.Next
}

currentNode.Next = node
}
}

func (queue *Queue) Dequeue() Item {
fmt.Println(" The queue is empty ")
return nil
}

return item
}

func (queue *Queue) Traverse() {
fmt.Println(" The queue is empty ")
return
}

for currentNode.Next != nil {
fmt.Printf("%v\t", currentNode.Data)
currentNode = currentNode.Next
}
fmt.Printf("%v\t", currentNode.Data)
}``````

#### Circular queue

##### Why is there a circular queue ？

Look at this situation , I have a length that is 5 Queues , The queue is full at the moment . Suppose I take it out of the head of the team now 3 After elements , Want to put data in the queue again , It can't be put in , Now there's a problem , The queue has free space , But you can't put data into the queue One of the solutions is , Data movement . But in that case , Every time we leave the team, we say that the index of the array is deleted 0 The elements of , And move all the data behind it forward , As a result, the time complexity of the team will be changed from the original O(1) become O(n), This method is obviously not desirable The second way is to use a Circular queue , It's obviously a ring , This is as like as two peas . What's the specific , Everyone should be very clear , The difficulty is to judge empty and full

`````` When the queue is empty ：tail == head
When the queue is full ：(tail+1)%n == head``````

Ah , Find the rules , No, just remember it , Let's take a look at how to achieve

##### Implementation of circular queue
``````package loopQueue

import "fmt"

type Item interface {}

const QueueSize = 5
type LoopQueue struct {
Items [QueueSize]Item
Tail int
}

//init
func (queue *LoopQueue) Init() {
queue.Tail = 0
}

//enqueue
func (queue *LoopQueue) Enqueue(data Item) {
if ((queue.Tail + 1) % QueueSize) == queue.Head {
fmt.Println(" The queue is full ")
}

queue.Items[queue.Tail] = data
queue.Tail = (queue.Tail+1) % QueueSize
}

//dequeue
func (queue *LoopQueue) Dequeue() Item {
fmt.Println(" The queue is empty ")
return nil
}

return item
}
``````

#### Application scenarios of queues

##### Blocking queues and concurrent queues
###### Blocking queues

in application , The queue won't be infinite , Once the queue has a length limit , There will be a full time , When the line is full , Queuing operations will be blocked , Because there's no data to take . And when the queue is empty , Out of the team is blocked , Until there is data available in the queue

you 're right , Usually used producer - Consumer model this is it , A producer can be easily implemented through queues - Consumer model

Based on the blocking queue , You can also adjust “ producer ” and “ consumer ” The number of , To improve the efficiency of data processing

###### Concurrent queues

For the blocking queue above , In the case of multithreading , There will be multiple threads working on the queue at the same time , At this time, there will be thread safety problems （ If you want to understand the underlying causes , You can see my article ： Process synchronization in process management

The queue that guarantees thread safety is called concurrent queue , The easiest way is to lock in and out of the team . About locks , You can also see my series here ： Thread lock series Reference material ：

• The beauty of data structure and algorithm
• Learning data structures from zero