Fancy DSA Fancy DSA
数据结构
算法
LeetCode
  • 关于
  • 导航 (opens new window)
  • 分类
  • 标签
  • 归档
设计模式 (opens new window)
博客 (opens new window)
GitHub (opens new window)

Jonsam NG

想的更多,也要想的更远
数据结构
算法
LeetCode
  • 关于
  • 导航 (opens new window)
  • 分类
  • 标签
  • 归档
设计模式 (opens new window)
博客 (opens new window)
GitHub (opens new window)
  • 开始上手
  • Plan 计划
  • Roadmap 路线
  • 术语表
  • 数据结构简介
  • queue 队列

    • Queue [队列]
    • PriorityQueue [优先队列]
    • MinPriorityQueue [最小优先队列]
    • MaxPriorityQueue [最大优先队列]
    • Deque(double-ended queue) [双端队列]
    • CircularQueue [循环队列]
      • 介绍
      • 用法
      • 工作机制
      • 实现
      • 应用
      • 参考
  • heap 堆

  • linked-list 链表

  • stack 栈

  • set 集合

  • graph 图

  • tree 树

  • vectors 矢量

  • 数据结构
  • queue 队列
jonsam
2022-09-26
目录

CircularQueue [循环队列]

# 介绍

圆形缓冲区(circular buffer),也称作圆形队列(circular queue),循环缓冲区(cyclic buffer),环形缓冲区(ring buffer),是一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流。

# 用法

圆形缓冲区的一个有用特性是:当一个数据元素被用掉后,其余数据元素不需要移动其存储位置。相反,一个非圆形缓冲区(例如一个普通的队列)在用掉一个数据元素后,其余数据元素需要向前搬移。换句话说,圆形缓冲区适合实现先进先出缓冲区,而非圆形缓冲区适合后进先出缓冲区。

圆形缓冲区适合于事先明确了缓冲区的最大容量的情形。扩展一个圆形缓冲区的容量,需要搬移其中的数据。因此一个缓冲区如果需要经常调整其容量,用链表实现更为合适。

写操作覆盖圆形缓冲区中未被处理的数据在某些情况下是允许的。特别是在多媒体处理时。例如,音频的生产者可以覆盖掉声卡尚未来得及处理的音频数据。

# 工作机制

由于计算机内存是线性地址空间,因此圆形缓冲区需要特别的设计才可以从逻辑上实现。

读指针与写指针:

一般的,圆形缓冲区需要 4 个指针:

  • 在内存中实际开始位置;
  • 在内存中实际结束位置,也可以用缓冲区长度代替;
  • 存储在缓冲区中的有效数据的开始位置(读指针);
  • 存储在缓冲区中的有效数据的结尾位置(写指针)。

读指针、写指针可以用整型值来表示。

扩展:生产者消费者问题,参见:操作系统原理之进程同步 (opens new window)

# 实现

# JavaScript

// Circular Queues offer a quick to store FIFO data with a maximum size.
// Conserves memory as we only store up to our capacity
// It is opposed to a queue which could continue to grow if input outpaces output
// Doesn’t use dynamic memory so No memory leaks

class CircularQueue {
  constructor (maxLength) {
    this.queue = []
    this.front = 0
    this.rear = 0
    this.maxLength = maxLength
  }

  // ADD ELEMENTS TO QUEUE
  enqueue (value) {
    if (this.checkOverflow()) return
    if (this.checkEmpty()) {
      this.front += 1
      this.rear += 1
    } else {
      if (this.rear === this.maxLength) {
        this.rear = 1
      } else this.rear += 1
    }
    this.queue[this.rear] = value
  }

  // REMOVES ELEMENTS
  dequeue () {
    if (this.checkEmpty()) {
      // UNDERFLOW
      return
    }
    const y = this.queue[this.front]
    this.queue[this.front] = '*'
    if (!this.checkSingleelement()) {
      if (this.front === this.maxLength) this.front = 1
      else {
        this.front += 1
      }
    }

    return y // Returns the removed element and replaces it with a star
  }

  // checks if the queue is empty or not
  checkEmpty () {
    if (this.front === 0 && this.rear === 0) {
      return true
    }
  }

  checkSingleelement () {
    if (this.front === this.rear && this.rear !== 0) {
      this.front = this.rear = 0
      return true
    }
  }

  // Checks if max capacity of queue has been reached or not
  checkOverflow () {
    if ((this.front === 1 && this.rear === this.maxLength) || (this.front === this.rear + 1)) {
      // CIRCULAR QUEUE OVERFLOW
      return true
    }
  }

  // Prints the entire array ('*' represents blank space)
  display (output = value => console.log(value)) {
    for (let index = 1; index < this.queue.length; index++) {
      output(this.queue[index])
    }
  }

  // Displays the length of queue
  length () {
    return this.queue.length - 1
  }

  // Display the top most value of queue
  peek () {
    return this.queue[this.front]
  }
}

export { CircularQueue }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

# 应用

# 卡牌序列问题

// see https://gist.github.com/tinylamb/9228640
/*
 * =========================================================
 *       Filename:  throwcards.c
 *    Description:  google Throwing cards away I
 *    题目大意:给n张牌,放成一叠,从上到下编号从1到n,当至少还有两张牌时
 *    丢弃最上面的牌,然后把新的最上面的牌放到最下面,一直重复,直到只剩下一张牌
 *    输出丢弃牌的序列。
 * =========================================================
 */
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#define MAX 51 //预先知道数组最大值,留一个空来区别空/满

/*数据集定义*/
typedef struct Queue{
    int array[MAX];
    int head,tail;
}Queue;

/*queue上的基本操作*/
void InitQueue(Queue *q);
bool IsEmpty(Queue *q);
bool IsFull(Queue *q);
void InQueue(Queue *q,int e);
int DeQueue(Queue *q);

int main(){
    int n;
    int discards[MAX];
    Queue q;
    while(scanf("%d",&n)!=EOF && n){
        InitQueue(&q);
        int i;
        for(i=1;i<=n;i++)
            InQueue(&q,i);
        int k=0;
        while(!IsEmpty(&q)){
            discards[k++]=DeQueue(&q);
            int top=DeQueue(&q);
            InQueue(&q , top);
        }
        printf("Discarded cards:");
        for(i=0;i<n-1;i++)
            printf("%d%s",discards[i],(i==n-2)?"\n":",");
        printf("Remaining card:%d\n",discards[i]);
    }
    return 0;
}

void InitQueue(Queue *q){
    q->head=q->tail=0;
}
bool IsEmpty(Queue *q){
    return (q->head==q->tail)?true:false;
}

bool IsFull(Queue *q){
    return ((q->tail + 1) % MAX == q->head)?true:false;
}

void InQueue(Queue *q,int e){
    assert(!IsFull(q));
    q->array[q->tail]=e;
    q->tail = (q->tail+1) % MAX;
}
int DeQueue(Queue *q){
    assert(!IsEmpty(q));
    int e=q->array[q->head];
    q->head = (q->head + 1) % MAX;
    return e;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

# 参考

  • 环形缓冲区 - Wikiwand (opens new window)
编辑 (opens new window)
上次更新: 2022/10/13, 15:33:21
Deque(double-ended queue) [双端队列]
Heap [堆]

← Deque(double-ended queue) [双端队列] Heap [堆]→

最近更新
01
0-20题解
10-31
02
本章导读
10-31
03
算法与转换:Part1
10-28
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Fancy DSA | Made by Jonsam by ❤
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式