Golang數據結構 - 3 - 隊列

  ______      __    __   _______  __    __   _______ 
 /  __  \    |  |  |  | |   ____||  |  |  | |   ____|
|  |  |  |   |  |  |  | |  |__   |  |  |  | |  |__   
|  |  |  |   |  |  |  | |   __|  |  |  |  | |   __|  
|  `--'  '--.|  `--'  | |  |____ |  `--'  | |  |____ 
 \_____\_____\\______/  |_______| \______/  |_______|

上一章中我們學習了棧以及棧的基本操作,并使用數組切片和鏈表來實現了兩種不同的棧操作方式,接下來我們將學習并實現隊列。

隊列與棧非常相似,但是元素的出入原則與棧不同,在棧中元素是以后進先出(LIFO)的原則進行的,而在隊列中元素以先進先出(FIFO)的原則進行。

隊列與棧類似,是一種特殊的線性表,它只允許在表的前端進行插入操作,也只允許在表的后端進行彈出操作。進行插入操作的一端稱為隊尾,而進行刪除操作的一端則稱為隊頭。

本章將基于Go數組切片、鏈表來實現隊列的基本操作,同時實現雙端隊列,最終探討循環隊列的特性以及應用。

隊列定義

首先對隊列定義如下基本操作接口:

  • Enqueue(e ...Element):添加若干元素入隊
  • Dequeue() Element:隊首元素出隊
  • Peek() Element:獲取隊首元素,不出隊
  • Empty() bool:隊列是否為空
  • Size() int:返回隊隊列大小
  • Clear():清空隊列

代碼如下

type Element interface{}

type Queue interface {
    // 入隊
    Enqueue(e ...Element)
    // 出隊
    Dequeue() Element

    // 獲取隊首元素,不出隊
    Peek() Element

    // 隊列是否為空你
    Empty() bool

    // 返回隊列大小
    Size() int
    
    // 清空隊列
    Clear()
}

向隊列添加元素

  1. 數組切片實現
// 入隊操作
func (s *ArrayQueue) Enqueue(e ...Element) {
    *s = append(*s, e...)
}
  1. 鏈表實現
func (s *LinkedQueue) Enqueue(e ...Element) {
    for _, v := range e {
        s.Tail.Next = &node{
            Value: v,
            Next:  nil,
        }
        s.Tail = s.Tail.Next
        s.size++
    }
}

從隊列移除元素

  1. 數組切片實現
// 出隊
func (s *ArrayQueue) Dequeue() Element {
    if s.Empty() {
        return nil
    }
    first := (*s)[0]

    // 出隊操作
    *s = (*s)[1:]
    return first
}
  1. 鏈表實現
func (s *LinkedQueue) Dequeue() Element {
    if s.Empty() {
        return nil
    }
    first := s.Head.Next.Value

    // 出隊
    s.Head = s.Head.Next
    s.size--
    return first
}

查看隊列頭元素

  1. 數組切片實現
// 獲取隊首元素,不出隊
func (s *ArrayQueue) Peek() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[0]
}
  1. 鏈表實現
func (s *LinkedQueue) Peek() Element {
    if s.Empty() {
        return nil
    }
    return s.Head.Next.Value
}

獲取隊列長度

  1. 數組切片實現
// 返回隊列大小
func (s *ArrayQueue) Size() int {
    return len(*s)
}
  1. 鏈表實現
func (s *LinkedQueue) Size() int {
    return s.size
}

檢查隊列是否為空

  1. 數組切片實現
// 隊列是否為空
func (s *ArrayQueue) Empty() bool {
    return s.Size() == 0
}
  1. 鏈表實現
func (s *LinkedQueue) Empty() bool {
    return s.Head == s.Tail
}

清空隊列

  1. 數組切片實現
// 清空隊列
func (s *ArrayQueue) Clear() {
    *s = ArrayQueue{}
}
  1. 鏈表實現
func (s *LinkedQueue) Clear() {
    s.Head.Next = nil
    s.Tail = s.Head
    s.size = 0
}

雙端隊列

雙端隊列也是在現實中非常常用的一種數據結構,它允許我們在隊列的兩端進行添加和刪除操作。
在本章中雙端隊列的實現主要有以下接口:

  • AddFront(e ...Element):向隊首添加元素
  • AddBack(e ...Element):向隊尾添加元素
  • RemoveFront() Element:移除隊首元素
  • RemoveBack() Element:移除隊尾元素
  • PeekFront() Element:查看隊首元素,不出隊
  • PeekBack() Element:查看隊尾元素,不出隊
  • Size() int:獲取隊列長度
  • Empty() bool:判斷隊列是否為空

向隊首添加元素

func (s *ArrayDeque) AddFront(e ...Element) {
    ln := len(e)
    rev := make([]Element, ln)
    for i, v := range e {
        rev[ln-i-1] = v
    }
    *s = append(rev, *s...)
}

向隊尾添加元素

func (s *ArrayDeque) AddBack(e ...Element) {
    *s = append(*s, e...)
}

移除隊首元素

func (s *ArrayDeque) RemoveFront() Element {
    if s.Empty() {
        return nil
    }
    v := (*s)[0]

    // 出隊
    *s = (*s)[1:]
    return v

}

移除隊尾元素

func (s *ArrayDeque) RemoveBack() Element {
    if s.Empty() {
        return nil
    }
    ln := len(*s)
    v := (*s)[ln-1]

    // 出隊
    *s = (*s)[:ln-1]
    return v
}

查看隊首元素

func (s *ArrayDeque) PeekFront() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[0]
}

查看隊尾元素

func (s *ArrayDeque) PeekBack() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[len(*s)-1]
}

獲取隊列長度

func (s *ArrayDeque) Size() int {
    return len(*s)
}

隊列是否為空

func (s *ArrayDeque) Empty() bool {
    return s.Size() == 0
}

完整實現代碼

隊列

package main

import "fmt"

type Element interface{}

type Queue interface {
    // 入隊
    Enqueue(e ...Element)
    // 出隊
    Dequeue() Element

    // 獲取隊首元素,不出隊
    Peek() Element

    // 隊列是否為空你
    Empty() bool

    // 返回隊列大小
    Size() int

    // 清空隊列
    Clear()
}

// 使用數組切片實現的隊列
type ArrayQueue []Element

// 入隊操作
func (s *ArrayQueue) Enqueue(e ...Element) {
    *s = append(*s, e...)
}

// 出隊
func (s *ArrayQueue) Dequeue() Element {
    if s.Empty() {
        return nil
    }
    first := (*s)[0]

    // 出隊操作
    *s = (*s)[1:]
    return first
}

// 獲取隊首元素,不出隊
func (s *ArrayQueue) Peek() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[0]
}

// 隊列是否為空
func (s *ArrayQueue) Empty() bool {
    return s.Size() == 0
}

// 返回隊列大小
func (s *ArrayQueue) Size() int {
    return len(*s)
}

// 清空隊列
func (s *ArrayQueue) Clear() {
    *s = ArrayQueue{}
}

func NewArrayQueue() Queue {
    return &ArrayQueue{}
}

type node struct {
    Value Element
    Next  *node
}

// 使用鏈表實現的隊列
// 這里使用帶有頭尾節點的鏈表
type LinkedQueue struct {
    Head *node
    Tail *node
    size int
}

func (s *LinkedQueue) Enqueue(e ...Element) {
    for _, v := range e {
        s.Tail.Next = &node{
            Value: v,
            Next:  nil,
        }
        s.Tail = s.Tail.Next
        s.size++
    }
}

func (s *LinkedQueue) Dequeue() Element {
    if s.Empty() {
        return nil
    }
    first := s.Head.Next.Value

    // 出隊
    s.Head = s.Head.Next
    s.size--
    return first
}

func (s *LinkedQueue) Peek() Element {
    if s.Empty() {
        return nil
    }
    return s.Head.Next.Value
}

func (s *LinkedQueue) Empty() bool {
    return s.Head == s.Tail
}

func (s *LinkedQueue) Size() int {
    return s.size
}

func (s *LinkedQueue) Clear() {
    s.Head.Next = nil
    s.Tail = s.Head
    s.size = 0
}

func NewLinkedQueue() Queue {
    head := &node{}
    return &LinkedQueue{
        Head: head,
        Tail: head,
        size: 0,
    }
}

func main() {
    q := NewArrayQueue()
    //q := NewLinkedQueue()

    fmt.Println("Empty:", q.Empty())
    fmt.Println("Size:", q.Size())

    q.Enqueue(1, 2, 3, 4, 5, 6)
    fmt.Println("Enqueue 1,2,3,4,5,6")
    fmt.Println("Size:", q.Size())
    fmt.Println("Peek:", q.Peek())

    fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue(), q.Dequeue())
    fmt.Println("Size:", q.Size())
    fmt.Println("Empty:", q.Empty())

    fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue(), q.Dequeue())
    fmt.Println("Size:", q.Size())

    fmt.Println("Empty:", q.Empty())

    fmt.Println("Enqueue:1,2,3")
    q.Enqueue(1, 2, 3)

    fmt.Println("Dequeue:", q.Dequeue(), q.Dequeue())

    fmt.Println("Clear")
    q.Clear()
    fmt.Println("Empty:", q.Empty(), "Size:", q.Size())

}

運行結果

Empty: true
Size: 0
Enqueue 1,2,3,4,5,6
Size: 6
Peek: 1
Dequeue: 1 2 3
Size: 3
Empty: false
Dequeue: 4 5 6
Size: 0
Empty: true
Enqueue:1,2,3
Dequeue: 1 2
Clear
Empty: true Size: 0

Process finished with exit code 0

雙端隊列

package main

import "fmt"

type Element interface{}

type Deque interface {
    // 向隊首添加元素
    AddFront(e ...Element)

    // 向隊尾添加元素
    AddBack(e ...Element)

    // 隊首元素出隊
    RemoveFront() Element

    // 隊尾元素出隊
    RemoveBack() Element

    // 查看隊首元素
    PeekFront() Element

    // 查看隊尾元素
    PeekBack() Element

    // 隊列長度
    Size() int

    // 隊列是否為空
    Empty() bool
}

type ArrayDeque []Element

func (s *ArrayDeque) AddFront(e ...Element) {
    ln := len(e)
    rev := make([]Element, ln)
    for i, v := range e {
        rev[ln-i-1] = v
    }
    *s = append(rev, *s...)
}

func (s *ArrayDeque) AddBack(e ...Element) {
    *s = append(*s, e...)
}

func (s *ArrayDeque) RemoveFront() Element {
    if s.Empty() {
        return nil
    }
    v := (*s)[0]

    // 出隊
    *s = (*s)[1:]
    return v

}

func (s *ArrayDeque) RemoveBack() Element {
    if s.Empty() {
        return nil
    }
    ln := len(*s)
    v := (*s)[ln-1]

    // 出隊
    *s = (*s)[:ln-1]
    return v
}

func (s *ArrayDeque) PeekFront() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[0]
}

func (s *ArrayDeque) PeekBack() Element {
    if s.Empty() {
        return nil
    }
    return (*s)[len(*s)-1]
}

func (s *ArrayDeque) Size() int {
    return len(*s)
}

func (s *ArrayDeque) Empty() bool {
    return s.Size() == 0
}

func NewArrayDeque() Deque {
    return &ArrayDeque{}
}

func main() {

    dq := NewArrayDeque()

    dq.AddFront(1, 2, 3, 4, 5, 6, 7, 8, 9)
    fmt.Println("AddFront: 1,2,3,4,5,6,7,8,9")

    fmt.Println("RemoveFront:", dq.RemoveFront(), dq.RemoveFront())

    fmt.Println("RemoveBack:", dq.RemoveBack(), dq.RemoveBack())

}

運行結果

AddFront: 1,2,3,4,5,6,7,8,9
RemoveFront: 9 8
RemoveBack: 1 2

Process finished with exit code 0
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容