标签:type strong 循环 开始 速度 移除 alt fifo tail
队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾(tail)。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素(head)。
下面我用golang来实现循环队列,但需要注意,程序中tailIndex所指引的是最后一个插入的元素(即真实的队尾元素),而非插入元素的下一个位置(许多其他实现采用,详见B站视频)。这有很大区别,此时 队尾与队首的关系为:
tailIndex = (headIndex+count?1) % capacity
新增元素:
tailIndex = (tailIndex+1) % capacity
--->  tailIndex = (headIndex+count) % capacity
删除元素:
headIndex = (headIndex+1) % capacity
下面图表示队列容量为5,长度为3实现时head与tail所指位置:
程序利用了取模运算,共定义了四个属性:数组;队首索引;队列长度;队列容量
/*
   enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
   deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
   MyCircularQueue(k): 构造器,设置队列长度为 k 。
   Front: 从队首获取元素。如果队列为空,返回 -1 。
   Rear: 获取队尾元素。如果队列为空,返回 -1 。
   isEmpty(): 检查循环队列是否为空。
   isFull(): 检查循环队列是否已满。
*/
type MyCircularQueue struct {
	queue     []int // 一个固定大小的数组,用于保存循环队列的元素
	headIndex int   // 一个整数,保存队首 head 的索引
	count     int   // 循环队列当前的长度,即循环队列中的元素数量。
	// tailIndex = (headIndex+count?1) % capacity , 因此不需要队尾属性
	capacity  int   // 循环队列的容量,即队列中最多可以容纳的元素数量。
}
/** Initialize your data structure here. Set the size of the queue to be k. */
func Constructor(k int) MyCircularQueue {
	return MyCircularQueue{
		queue:     make([]int, k, k),
		headIndex: 0,
		count:     0,
		capacity:  k,
	}
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
// 向循环队列插入一个元素。如果成功插入则返回真
func (m *MyCircularQueue) EnQueue(value int) bool {
	if m.IsFull() {
		return false
	}
	// 既定公式,令队尾+1 = value
	/*
	这里需要注意,是令队尾的下一个元素 = value
	即: m.queue[(m.headIndex+m.count-1+1)%m.capacity] = value
	*/
	m.queue[(m.headIndex+m.count)%m.capacity] = value
	m.count++
	return true
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
// 从循环队列中删除一个元素。如果成功删除则返回真
func (m *MyCircularQueue) DeQueue() bool {
	if m.IsEmpty() {
		return false
	}
	m.headIndex = (m.headIndex + 1) % m.capacity
	m.count--
	return true
}
/** Get the front item from the queue. */
// 从队首获取元素。如果队列为空,返回 -1
func (m *MyCircularQueue) Front() int {
	if m.IsEmpty() {
		return -1
	}
	return m.queue[m.headIndex]
}
/** Get the last item from the queue. */
// 从队尾获取元素。如果队列为空,则返回 -1
func (m *MyCircularQueue) Rear() int {
	if m.IsEmpty() {
		return -1
	}
	return m.queue[(m.headIndex+m.count-1)%m.capacity]
}
/** Checks whether the circular queue is empty or not. */
// 检查循环队列是否为空
func (m *MyCircularQueue) IsEmpty() bool {
	return m.count == 0
}
/** Checks whether the circular queue is full or not. */
// 检查循环队列是否已满
func (m *MyCircularQueue) IsFull() bool {
	return m.count == m.capacity
}
/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * obj := Constructor(k);
 * param_1 := obj.EnQueue(value);
 * param_2 := obj.DeQueue();
 * param_3 := obj.Front();
 * param_4 := obj.Rear();
 * param_5 := obj.IsEmpty();
 * param_6 := obj.IsFull();
 */
这种方法略微取巧,不需要取模运算,但是实际运算速度也差不太多,还不容易理解.....
判空:head == tail
判满:tail + 1 == head,数组越界时需要转换
有两点需要额外注意:
程序共定义了四个属性:数组;队首索引;队尾索引;队列长度(多加一个用于给tail指针站位)
直接上代码:
/*
   MyCircularQueue(k): 构造器,设置队列长度为 k 。
   enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
   deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
   Front: 从队首获取元素。如果队列为空,返回 -1 。
   Rear: 获取队尾元素。如果队列为空,返回 -1 。
   isEmpty(): 检查循环队列是否为空。
   isFull(): 检查循环队列是否已满。
*/
// head为序列元素的上标,即队首,tail为序列的下标,即队尾,size为数组长度
type MyCircularQueue struct {
   data  []int
   head  int
   tail  int
   size  int
}
/** Initialize your data structure here. Set the size of the queue to be k. */
func Constructor(k int) MyCircularQueue {
   return MyCircularQueue{
      data: make([]int, k + 1, k + 1), // 确定data长度,容量
      head: 0,
      tail: 0,
      size: k + 1, // 多加一个用于给tail指针站位
   }
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
// 向循环队列插入一个元素。如果成功插入则返回真
func (m *MyCircularQueue) EnQueue(value int) bool {
   // 如果序列已经满了,返回false
   if m.IsFull() {
      return false
   }
   // 向数组起始位置插入value,下标+1
   m.data[m.tail] = value
   m.tail++
   // 如果下标达到数组最后一个元素位置(等于size长度,这个位置是为tail准备的,不存储元素)下标归0 ---> 开始循环
   if m.tail == m.size {
      m.tail = 0
   }
   return true
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
// 从循环队列中删除一个元素。如果成功删除则返回真。
func (m *MyCircularQueue) DeQueue() bool {
   // 如果队列是空的,返回false
   if m.IsEmpty() {
      return false
   }
   // 序列 head+1,如果到头了就归0 ---> 循环 <原理同上>
   m.head++
   if m.head == m.size {
      m.head = 0
   }
   return true
}
/** Get the front item from the queue. */
// 从队首获取元素。如果队列为空,返回 -1
func (m *MyCircularQueue) Front() int {
   if m.IsEmpty() {
      return -1
   }
   return m.data[m.head]
}
/** Get the last item from the queue. */
// 获取队尾元素。如果队列为空,返回 -1
func (m *MyCircularQueue) Rear() int {
   if m.IsEmpty() {
      return -1
   }
   // 边界问题,tail独占一个空间,因此要取的index为tail前一个位置
   lastIndex := m.tail - 1
   if lastIndex < 0 {
      lastIndex = m.size - 1
   }
   return m.data[lastIndex]
}
/** Checks whether the circular queue is empty or not. */
// 检查队列是否为空
func (m *MyCircularQueue) IsEmpty() bool {
   // 只要相等,队列即为空
   return m.head == m.tail
}
/** Checks whether the circular queue is full or not. */
// 检查队列是否已满
func (m *MyCircularQueue) IsFull() bool {
    // tail + 1 == head 时队列已满
   next := m.tail + 1
    // 越界问题处理
   if next == m.size {
      next = 0
   }
   return next == m.head
}
/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * obj := Constructor(k);
 * param_1 := obj.EnQueue(value);
 * param_2 := obj.DeQueue();
 * param_3 := obj.Front();
 * param_4 := obj.Rear();
 * param_5 := obj.IsEmpty();
 * param_6 := obj.IsFull();
 */
待定吧,慢慢来
标签:type strong 循环 开始 速度 移除 alt fifo tail
原文地址:https://www.cnblogs.com/newbase/p/12881348.html