用go实现队列

队列的定义

队列,和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构,与栈结构不同的是,队列的两端都"开口",要求数据只能从一端进,从另一端出。队列有两种存储方式,分别是顺序队和链队,今天实现的是链队。

结构的定义

队列需要两个指针定位对头和队尾的位置,所以定义方式如下所示。

// 代表每一个节点
type node struct {
	data interface{}
	next *node
}

type queue struct {
	// 头节点
	head *node

	// 队尾节点
	rear *node

	size int

	sync.Mutex
}

队列的相关操作

初始化队列

func newQueue() *queue {
	q := new(queue)
	q.head = nil
	q.rear = nil
	q.size = 0
	return q
}

创建一个心得队列对象,同时将头指针和尾指针全部置为nil

入队

// Put 尾插法
func (q *queue) Put(element interface{})  {
	n := new(node)
	n.data = element
	q.Lock()
	defer q.Unlock()

	if q.rear == nil {
		q.head = n
		q.rear = n
	}else {
		q.rear.next = n
		q.rear = n
	}
	q.size ++
}

// PutHead 头插法,在队列头部插入一个元素
func (q *queue) PutHead(element interface{})  {
	n := new(node)
	n.data = element
	q.Lock()
	defer q.Unlock()
	if q.head == nil {
		q.head = n
		q.rear = n
	}else {
		n.next = q.head
		q.head = n
	}
	q.size ++
}

入队分为两种方式,分别是头插法和尾插法,默认采用尾插法。

尾插法入队,首先创建一个节点对象,判断队列此时是否为空,若为空则将头指针和尾指针都指向该节点,否则将尾指针的节点的指针域指向新创建的节点,然后将队列的尾指针指向该节点。

出队

// Get 获取并删除队列头部的元素
func (q *queue) Get() interface{} {
	if q.head == nil {
		return nil
	}
	n := q.head
	q.Lock()
	defer q.Unlock()
	// 代表队列中仅一个元素
	if n.next == nil {
		q.head = nil
		q.rear = nil

	}else {
		q.head = n.next
	}
	q.size--
	return n.data
}

出队默认从对头取出元素,首先判断队列是否存在元素,若不存在则返回nil,若存在,则将头节点赋值,然后判断队列中是否只存在一个元素,若只存在一个元素则将头尾节点都置为nil,否则将头节点置为该节点的下一个节点。

测试


func main() {
	q := newQueue()
	q.Put(1)
	q.Put(2)
	fmt.Println(q.Get())
	fmt.Println(q.Get())
	fmt.Println("队列中剩余元素个数",q.size)
}

// 1
// 2
// 队列中剩余元素个数 0


个人博客https://vtsqr.xyz

上一篇:《剑指Offer》24-反转链表


下一篇:如何区分多数据源? | 带你读《SpringBoot实战教程》之二十二