go 數據結構之 隊列

下面先介紹下什麼是隊列:

(1)隊列是一個有序列表,可以用數組或是鏈表來實現。

(2)遵循先入先出的原則,即:先存入隊列的數據,要先取出,後存入的要後取出。

這裏用Go 實現一個一次性的隊列

package main

import (
	"errors"
	"fmt"
)

type Query struct {
	maxSize int		//最大容量
	array   [4]int	//數組
	head    int		//隊首指針
	tail    int		//隊尾指針
}

//初始化一個Query,注意這裏head和tail都爲-1
func NewQueue()*Query  {
	return &Query{
		maxSize: 4,
		head: -1,
		tail: -1,
	}
}

//這裏注意push時隊尾tail向後移動一位
func (q *Query)Push(val int) error{
	if q.tail == q.maxSize-1{
		return errors.New("隊列已滿")
	}
	q.tail ++
	q.array[q.tail] = val
	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",q.head,q.tail,q.array)
	return nil
}

//這裏注意pop時隊首head向後移動一位
func (q *Query)Pop()(val int ,err error){
	if q.head == q.tail{
		return 0,errors.New("隊列爲空")
	}
	q.head ++
	val = q.array[q.head]
	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",q.head,q.tail,q.array)
	return
}

func main() {
	query := NewQueue()
	query.Push(1) //隊首指針爲:-1 ---隊尾指針爲:0 ---隊列數組爲:[1 0 0 0] 因爲push時隊尾指針向後移動一位,所以隊尾指針由-1變爲0
	query.Push(2)//隊首指針爲:-1 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0]
	v,_:=query.Pop()//隊首指針爲:0 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0] 因爲pop是隊首指針向後移動一位,所以隊首指針由-1變爲0
	fmt.Println(v) // 1
	query.Push(3)	//隊首指針爲:0 ---隊尾指針爲:2 ---隊列數組爲:[1 2 3 0]
	query.Push(4)	//隊首指針爲:0 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
	v1,_:=query.Pop()//隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
	fmt.Println(v1)//2
	v2,_:=query.Pop()//隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
	fmt.Println(v2)//3
	v3,_:=query.Pop()// 隊首指針爲:3 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4] 注意這時隊首指針與隊尾指針都爲maxsize -1 時,此時數組無法在用,
	fmt.Println(v3) //4

}

下面是打印結果

GOROOT=C:\Go #gosetup
GOPATH=E:\gopath #gosetup
C:\Go\bin\go.exe build -o C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__1_.exe E:\gopath\src\dataStructure\隊列.go #gosetup
C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__1_.exe #gosetup
隊首指針爲:-1 ---隊尾指針爲:0 ---隊列數組爲:[1 0 0 0]
隊首指針爲:-1 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0]
隊首指針爲:0 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0]
1
隊首指針爲:0 ---隊尾指針爲:2 ---隊列數組爲:[1 2 3 0]
隊首指針爲:0 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
2
隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
3
隊首指針爲:3 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
4

上面這種寫法有一個弊端,就是這個隊列只能使用一次,當隊首指針和隊尾指針同時爲maxSize-1時,這個隊列就不能用了,下面是改進的環形隊列
在這裏插入圖片描述

package main

import (
	"errors"
	"fmt"
)

type cycleQueue struct {
	maxSize int
	array [4]int
	tail int
	head int
}

func newCycleQueue()*cycleQueue  {
	return &cycleQueue{
		maxSize: 4, //這裏實際只能存放三個元素
		tail: 0,
		head: 0,
	}
}

func (c *cycleQueue)Push(val int) error{
	if c.tail + 1  == c.maxSize{
		fmt.Println("隊列已滿")
		return errors.New("隊列已滿")
	}
	c.array[c.tail] =val
	c.tail = (c.tail+1) % c.maxSize
	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",c.head,c.tail,c.array)
	return nil
}

func (c *cycleQueue)Pop()(val int,err error){
	if c.head == c.tail{
		fmt.Println("隊列爲空")
		return -1,errors.New("隊列爲空")
	}

	val = c.array[c.head]
	c.head = (c.head + 1) % c.maxSize

	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",c.head,c.tail,c.array)
	return
}

func (c *cycleQueue)Show()  {
	for i:=c.head;i<=c.tail-1;i++{
		fmt.Printf("%d\t",c.array[i])
	}
	fmt.Println()
}

func main(){
	cyc := newCycleQueue()
	cyc.Push(1) //隊首指針爲:0 ---隊尾指針爲:1 ---隊列數組爲:[1 0 0 0]
	cyc.Show()//1
	cyc.Push(2)//隊首指針爲:0 ---隊尾指針爲:2 ---隊列數組爲:[1 2 0 0]
	cyc.Show()//1       2
	cyc.Push(3)//隊首指針爲:0 ---隊尾指針爲:2 ---隊列數組爲:[1 2 0 0]
	cyc.Show()//1       2       3
	cyc.Push(4)//隊列已滿
	cyc.Show()//1       2       3
	v,_:= cyc.Pop()//隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 0]
	fmt.Println(v)//1
	cyc.Show()//2       3
	v2,_:= cyc.Pop()//隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 0]
	fmt.Println(v2)//2
	cyc.Show()//3
}

下面是運行結果

GOROOT=C:\Go #gosetup
GOPATH=E:\gopath #gosetup
C:\Go\bin\go.exe build -o C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__3_.exe E:/gopath/src/dataStructure/環形隊列.go #gosetup
C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__3_.exe #gosetup
隊首指針爲:0 ---隊尾指針爲:1 ---隊列數組爲:[1 0 0 0]
1
隊首指針爲:0 ---隊尾指針爲:2 ---隊列數組爲:[1 2 0 0]
1       2
隊首指針爲:0 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 0]
1       2       3
隊列已滿
1       2       3
隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 0]
1
2       3
隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 0]
2
3

這種環形隊列最大的弊端就是要有一個空的元素始終沒有被用到,即實際只能存儲maxSize -1個元素,下面是環形隊列的改進版,是博主自己根據上面兩種隊列分析出來的,如有疑問歡迎留言,如有錯誤歡迎指出

package main

import (
	"errors"
	"fmt"
)

type cycleQueue2 struct {
	maxSize int
	array [4]int
	tail int
	head int
}

func newCycleQueue2()*cycleQueue2  {
	return &cycleQueue2{
		maxSize: 4,
		tail: -1,
		head: -1,
	}
}

func (c *cycleQueue2)Push(val int) error{
	if c.maxSize ==c.tail - c.head || (c.tail == c.head && c.tail != -1){
		fmt.Println("隊列已滿")
		return errors.New("隊列已滿")
	}
	c.tail = (c.tail+1) % c.maxSize
	c.array[c.tail] =val
	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",c.head,c.tail,c.array)
	return nil
}

func (c *cycleQueue2)Pop()(val int,err error){
	if c.head == c.tail && c.tail == -1{
		fmt.Println("隊列爲空")
		return -1,errors.New("隊列爲空")
	}
	c.head =( c.head + 1)%c.maxSize
	val = c.array[c.head]
	c.array[c.head] = 0

	if c.head  == c.tail {
		c.head ,c.tail= -1,-1
	}

	fmt.Printf("隊首指針爲:%d ---隊尾指針爲:%d ---隊列數組爲:%v\n",c.head,c.tail,c.array)
	return
}


func (c *cycleQueue2)Show()  {
	if c.head == c.tail && c.tail == -1{
		fmt.Println("隊列爲空")
		return
	}
	if c.maxSize ==c.tail - c.head || (c.tail == c.head && c.tail != -1){
		fmt.Println("隊列已滿")
		return
	}
	if c.head == c.tail {

	}else{
		for i:=c.head+1;i<=c.head+c.maxSize;i++{
			if c.array[i%c.maxSize] == 0{
				break
			}
			fmt.Printf("%d\t",c.array[i%c.maxSize])
		}
	}
	fmt.Println()
}

func main(){
	cyc := newCycleQueue2()
	cyc.Push(1)//隊首指針爲:-1 ---隊尾指針爲:0 ---隊列數組爲:[1 0 0 0]
	cyc.Show()//1
	cyc.Push(2)//隊首指針爲:-1 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0]
	cyc.Show()//1       2
	cyc.Push(3)//隊首指針爲:-1 ---隊尾指針爲:2 ---隊列數組爲:[1 2 3 0]
	cyc.Show()//1       2       3
	cyc.Push(4)//隊首指針爲:-1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
	cyc.Show()//1       2       3       4
	cyc.Push(4)//隊列已滿
	cyc.Show()//1       2       3       4
	v,_:= cyc.Pop()//隊首指針爲:0 ---隊尾指針爲:3 ---隊列數組爲:[0 2 3 4]
	fmt.Println(v)//1
	cyc.Show()//2       3       4
	v2,_:= cyc.Pop()//隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[0 0 3 4]
	fmt.Println(v2)//2
	cyc.Show()//3       4

	v3,_:= cyc.Pop()//隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[0 0 0 4]
	fmt.Println(v3)//3
	cyc.Show()//4

	v4,_:= cyc.Pop()//隊首指針爲:-1 ---隊尾指針爲:-1 ---隊列數組爲:[0 0 0 0]
	fmt.Println(v4)//4
	cyc.Show()//

	v5,_:= cyc.Pop()//隊列爲空
	fmt.Println(v5)//-1
	cyc.Show()//
}

下面是運行結果

GOROOT=C:\Go #gosetup
GOPATH=E:\gopath #gosetup
C:\Go\bin\go.exe build -o C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__2_.exe E:/gopath/src/dataStructure/隊列二.go #gosetup
C:\Users\v_licguo\AppData\Local\Temp\___go_build_dataStructure__2_.exe #gosetup
隊首指針爲:-1 ---隊尾指針爲:0 ---隊列數組爲:[1 0 0 0]
1
隊首指針爲:-1 ---隊尾指針爲:1 ---隊列數組爲:[1 2 0 0]
1       2
隊首指針爲:-1 ---隊尾指針爲:2 ---隊列數組爲:[1 2 3 0]
1       2       3
隊首指針爲:-1 ---隊尾指針爲:3 ---隊列數組爲:[1 2 3 4]
1       2       3       4
隊列已滿
1       2       3       4
隊首指針爲:0 ---隊尾指針爲:3 ---隊列數組爲:[0 2 3 4]
1
2       3       4
隊首指針爲:1 ---隊尾指針爲:3 ---隊列數組爲:[0 0 3 4]
2
3       4
隊首指針爲:2 ---隊尾指針爲:3 ---隊列數組爲:[0 0 0 4]
3
4
隊首指針爲:-1 ---隊尾指針爲:-1 ---隊列數組爲:[0 0 0 0]
4

隊列爲空
-1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章