03920171126数据结构环形队列
- 格式:docx
- 大小:21.70 KB
- 文档页数:2
C#环形队列的实现⽅法详解⼀、环形队列是什么队列是⼀种常⽤的数据结构,这种结构保证了数据是按照“先进先出”的原则进⾏操作的,即最先进去的元素也是最先出来的元素.环形队列是⼀种特殊的队列结构,保证了元素也是先进先出的,但与⼀般队列的区别是,他们是环形的,即队列头部的上个元素是队列尾部,通常是容纳元素数固定的⼀个闭环。
⼆、环形队列的优点 1.保证元素是先进先出的是由队列的性质保证的,在环形队列中通过对队列的顺序访问保证。
2.元素空间可以重复利⽤因为⼀般的环形队列都是⼀个元素数固定的⼀个闭环,可以在环形队列初始化的时候分配好确定的内存空间,当进队或出队时只需要返回指定元素内存空间的地址即可,这些内存空间可以重复利⽤,避免频繁内存分配和释放的开销。
3.为多线程数据通信提供了⼀种⾼效的机制。
在最典型的⽣产者消费者模型中,如果引⼊环形队列,那么⽣成者只需要⽣成“东西”然后放到环形队列中即可,⽽消费者只需要从环形队列⾥取“东西”并且消费即可,没有任何锁或者等待,巧妙的⾼效实现了多线程数据通信。
三、C#环形队列的实现看了⼀个数据结构的教程,是⽤C++写的,可⾃⼰C#还是⼀个菜鸟,更别说C++了,但还是⼤胆尝试⽤C#将其中的环形队列的实现写出来,先上代码:public class MyQueue<T> : IDisposable{private T[] queue;private int length;private int capacity;private int head = 0;private int tail = 0;public MyQueue(int capacity) {this.capacity = capacity;this.head = 0;this.tail = 0;this.length = 0;this.queue = new T[capacity];}public void Clear() {head = 0;tail = 0;length = 0;}public bool IsEmpty() {return length == 0;}public bool IsFull() {return length == capacity;}public int Length() {return length;}public bool EnQueue(T node) {if (!IsFull()) {queue[tail] = node;tail = (++tail) % capacity;length++;return true;}return false;}public T DeQueue() {T node = default(T);if (!IsEmpty()) {node = queue[head];head = (++head) % capacity;length--;}return node;}public void Traverse() {for (int i = head; i < length + head; i++) {Console.WriteLine(queue[i % capacity]);Console.WriteLine($"前⾯还有{i - head}个");}}public void Dispose() {queue = null;}}为了能够通⽤,所以⽤的是泛型来实现环形队列类。
数据结构-队列基本运算的实现及其应用篇一数据结构-队列基本运算的实现及其应用一、队列的基本概念队列是一种特殊的数据结构,它遵循先进先出(FIFO)的原则,即先进入队列的元素先出队列。
在队列中,新元素被添加到队列的末尾,而删除操作总是发生在队列的开头。
队列常用于解决各种问题,如处理事件、任务调度、缓冲处理等。
二、队列的基本操作队列的基本操作包括入队(enqueue)、出队(dequeue)、查看队首元素(peek)和判断队列是否为空。
入队操作:向队列的末尾添加一个新元素。
这个操作的时间复杂度通常为O(1),可以通过在队列的末尾添加元素来实现。
出队操作:删除队列开头的元素并返回它。
这个操作的时间复杂度通常为O(1),可以通过移除队列开头的元素来实现。
查看队首元素:返回队列开头的元素但不删除它。
这个操作的时间复杂度通常为O(1),可以通过返回队列开头的元素来实现。
判断队列是否为空:检查队列是否包含任何元素。
这个操作的时间复杂度通常为O(1),可以通过比较队列的长度和0来实现。
三、队列的实现队列可以通过不同的数据结构来实现,如数组、链表和循环列表等。
在这里,我们将介绍使用数组和链表来实现队列的基本操作。
使用数组实现队列使用数组实现队列时,我们需要保留一个空间来跟踪队列的开头和结尾。
通常,我们使用两个指针,一个指向队列的开头,另一个指向队列的结尾。
当我们在队列中添加一个新元素时,我们将它添加到结尾指针所指向的位置,并将结尾指针向后移动一位。
当我们要删除一个元素时,我们只需将开头指针向后移动一位并返回该位置的元素即可。
使用链表实现队列使用链表实现队列时,我们通常使用一个头指针指向队首元素,一个尾指针指向队尾元素的下一个位置。
入队操作时,我们在尾指针的位置创建一个新节点,并将尾指针移动到下一个位置。
出队操作时,我们只需删除头指针指向的节点,并将头指针移动到下一个位置。
四、队列的应用队列在计算机科学中有着广泛的应用,下面列举几个常见的例子:事件处理:在多线程编程中,队列经常用于事件驱动的系统来传递事件或消息。
【数据结构】C++语⾔⽆锁环形队列的实现⽆锁环形队列1.Ring_Queue在payload前加⼊⼀个头,来表⽰当前节点的状态2.当前节点的状态包括可以读、可以写、正在读、正在写3.当读完成后将节点状态改为可以写,当写完成后将节点状态改为可以读4.Ring_Queue使⽤时参照⽣产者消费者模型,⽣产者⽣产(写)⼀个可⽤节点,消费者获得(读)队列头节点/*************************************************************************************************** File Name : ring_queue_nolock.h* Created : 20 / 02 / 10* Author : GYT* Description : ⽆锁环形队列* 1.Ring_Queue在payload前加⼊⼀个头,来表⽰当前节点的状态* 2.当前节点的状态包括可以读、可以写、正在读、正在写* 3.当读完成后将节点状态改为可以写,当写完成后将节点状态改为可以读* 4.Ring_Queue使⽤时参照⽣产者消费者模型,⽣产者⽣产(写)⼀个可⽤节点,消费者获得(读)队列头节点**************************************************************************************************/#include <assert.h>#include <string.h>#include <sys/types.h>typedef unsigned char u_char;#define CAN_WRITE 0x00#define CAN_READ 0x01#define READING 0x02#define WRITING 0x03typedef struct tag{u_char tag_value;}TAG;class Ring_Queue{public:/*************************************************************************************************** Function Name : Ring_Queue* Description : 构造函数* Date : 20 / 02 / 10* Parameter : int nmemb:队列⼤⼩ int size:Payload长度* Return Code : none* Author : GYT**************************************************************************************************/Ring_Queue(int nmemb, int size):m_inmemb(nmemb), m_isize(size), m_iread_now(0), m_iwrite_now(0){if (nmemb <= 0 || size <= 0){assert(0);}m_queue_p = NULL;m_queue_p = new u_char[nmemb * (sizeof(TAG)+size)];memset(m_queue_p, 0, nmemb * (sizeof(TAG)+size));}/*************************************************************************************************** Function Name : Ring_Queue* Description : 析构函数* Date : 20 / 02 / 10* Parameter : none* Return Code : none* Author : GYT**************************************************************************************************/~Ring_Queue(){if (m_queue_p) delete[]m_queue_p;}/*************************************************************************************************** Function Name : Read* Description : 读取函数* Date : 20 / 02 / 10* Parameter : none* Return Code : 指向payload的指针* Author : GYT**************************************************************************************************/u_char * Read();/*************************************************************************************************** Function Name : Read_Over* Description : 读取之后的操作,将节点状态跟更新为‘可以写’,并将可读节点指向下⼀个位置 * Date : 20 / 02 / 10* Parameter : none* Return Code : none* Author : GYT**************************************************************************************************/void Read_Over();/*************************************************************************************************** Function Name : Write* Description : 写⼊函数* Date : 20 / 02 / 10* Parameter : none* Return Code : 此时返回⼀个安全的、可以⽤来写数据的指针,具体的写⼊操作由⽣产者执⾏ * Author : GYT**************************************************************************************************/u_char * Write();/*************************************************************************************************** Function Name : Write_Over* Description : 写⼊之后的操作,将节点状态跟更新为‘可以读’,并将可写节点指向下⼀个位置 * Date : 20 / 02 / 10* Parameter : none* Return Code : none* Author : GYT**************************************************************************************************/void Write_Over();private:/*************************************************************************************************** Function Name : queue_peek_nth* Description : 因为整个队列是u_char数组,需要根据字节数偏移⾄指定位置* Date : 20 / 02 / 10* Parameter : u_char *queue_p:队列 int pos:需要偏移的位置* Return Code : none* Author : GYT**************************************************************************************************/u_char *queue_peek_nth(u_char *queue_p, int pos);u_char* m_queue_p; //队列指针int m_inmemb; //队列⼤⼩int m_isize; //队列中存放数据的长度volatile int m_iread_now; //当前可读节点volatile int m_iwrite_now; //当前可写节点};#include "ring_queue_nolock.h"u_char * Ring_Queue::Read(){u_char * g_p = 0;TAG * tag_p = 0;u_char *user_data = 0;g_p = queue_peek_nth(m_queue_p, m_iread_now);tag_p = (TAG *)g_p;if (tag_p->tag_value == CAN_READ){user_data = (u_char *)g_p + sizeof(TAG);tag_p->tag_value = READING;}return user_data;}void Ring_Queue::Read_Over(){u_char * g_p = 0;TAG * tag_p = 0;g_p = queue_peek_nth(m_queue_p, m_iread_now);tag_p = (TAG *)g_p;if (tag_p->tag_value == READING){tag_p->tag_value = CAN_WRITE;m_iread_now = (m_iread_now + 1) % m_inmemb;}}u_char * Ring_Queue::Write(){u_char * g_p = 0;TAG * tag_p = 0;u_char *user_data = 0;g_p = queue_peek_nth(m_queue_p, m_iwrite_now);tag_p = (TAG *)g_p;if (tag_p->tag_value == CAN_WRITE){user_data = (u_char *)g_p + sizeof(TAG);tag_p->tag_value = WRITING;}return user_data;}void Ring_Queue::Write_Over(){u_char * g_p = 0;TAG * tag_p = 0;g_p = queue_peek_nth(m_queue_p, m_iwrite_now);tag_p = (TAG *)g_p;if (tag_p->tag_value == WRITING){tag_p->tag_value = CAN_READ;m_iwrite_now = (m_iwrite_now + 1) % m_inmemb;}}u_char* Ring_Queue::queue_peek_nth(u_char *queue_p, int pos) {u_char *rst = 0;if (queue_p && pos < m_inmemb){rst = queue_p + pos * (sizeof(TAG)+m_isize);}return rst;}。
c语言环形队列算法编写在计算机科学中,队列是一种基本的数据结构,它遵循先进先出(FIFO)的原则。
而环形队列则是队列的一种特殊形式,它的末尾和起点是相连的,形成一个环。
这种数据结构在许多实际应用中都非常有用,例如在操作系统中实现缓冲区,或在网络编程中处理数据包等。
下面,我们将介绍如何使用C语言实现环形队列。
一、环形队列的基本概念环形队列是一个固定大小的数组,它从数组的某个位置开始,直到数组的末尾,然后再回到数组的开始。
当队列满时,新元素将添加到队列的开始位置,形成了一个环形的结构。
二、C语言实现环形队列1.定义数据结构首先,我们需要定义一个结构体来表示队列中的元素。
通常包括一个整数类型的指针,指向队列中的下一个元素,以及一个指向队列大小的变量。
```ctypedefstruct{int*data;intfront;intrear;intsize;}CircularQueue;```2.初始化队列在创建环形队列时,我们需要初始化它的数据指针、队首和队尾指针以及队列大小。
```cvoidinitQueue(CircularQueue*queue){queue->front=0;queue->rear=0;queue->size=0;}```3.入队操作入队操作是将元素添加到队列的末尾。
在环形队列中,我们可以通过移动队尾指针来实现这个操作。
```cvoidenqueue(CircularQueue*queue,intvalue){if(queue->size==queue->size){//队列已满,需要扩展队列大小queue->size*=2;queue->data=realloc(queue->data,queue->size*sizeof(int));}queue->data[queue->rear]=value;queue->rear=(queue->rear+1)%queue->size;queue->size++;}```4.出队操作出队操作是从队列的开头移除一个元素。
环行队列的知识点总结一、环形队列的定义环形队列是一种特殊的队列,它采用循环数组的方式来实现。
环形队列和普通队列相比,能够更好地利用内存空间,减少内存的浪费。
二、环形队列的特点1. 采用循环数组存储数据,解决了普通队列在入队出队操作中浪费内存空间的问题;2. 使用两个指针来标识队头和队尾,实现循环队列的功能;3. 环形队列的长度固定,当队列满时,无法插入新的元素;4. 环形队列的插入和删除操作都具有较高的效率。
三、环形队列的基本操作1. 初始化:创建一个具有固定大小的环形队列,并初始化队头和队尾指针。
2. 入队操作:向队尾指针所指向的位置插入一个新的元素,并更新队尾指针。
3. 出队操作:删除队头指针所指向的元素,并更新队头指针。
4. 判空操作:当队列为空时,队头指针和队尾指针相等。
5. 判满操作:当队列满时,队尾指针的下一个位置等于队头指针。
四、环形队列的实现1. 环形队列可以采用数组来实现,同时需要两个指针来标识队头和队尾。
2. 入队操作:判断队列是否满,若满则无法插入新元素;若不满,则将新元素加入到队尾,并更新队尾指针。
3. 出队操作:判断队列是否空,若空则无法删除元素;若非空,则删除队头元素,并更新队头指针。
4. 注意循环数组的处理,当队尾指针到达数组的末尾时,需要将其指向数组的起始位置。
五、环形队列的应用1. 缓冲区:环形队列可以用于实现缓冲区,存储需要处理的数据。
2. 消息队列:在系统中,环形队列可以用作消息队列,实现进程间的通信。
3. 循环播放:在媒体播放器中,可以使用环形队列来实现音乐或视频的循环播放功能。
4. CPU调度:操作系统中可以使用环形队列来实现CPU的任务调度。
六、环形队列的优缺点1. 优点:能够更好地利用内存空间,减少内存的浪费;具有较高的效率和性能;2. 缺点:长度固定,无法动态扩展;插入和删除操作需要维护两个指针,实现稍复杂。
七、环形队列的应用场景1. 需要高效的队列数据结构;2. 内存空间有限,需要更好地利用内存;3. 需要循环存储数据的场合。
数据结构-环形队列-队列模板实现-c++代码⼀、队列(FIFO-first in first out)分类:普通队列:先进先出,读取时有两种:⼀种是指针移动向下读取;⼀种是每读取⼀个元素,后⾯的所有元素⾃动向前移动⼀个位置。
这两种办法都有缺点。
第⼀种会造成出栈后的数据的位置没有被重新利⽤,内存浪费。
第⼆种是每次读出⼀个元素,后⾯所有元素都前进移动,效率低下。
环形队列:预先设定环形队列可容纳值的⼤⼩,分头指针和尾指针指⽰队列的头和尾。
存储时存在尾指针位置,然后尾指针加⼀。
读取时读头指针位置,头指针加⼀。
这样所有的空间可以循环利⽤。
利⽤判空或判满函数来决定队列是否还有元素或者队列是否已满。
缺点是队列⼤⼩不可变,如果队列满了,就不能再加⼊新元素。
但是效率⾼,空间利⽤同样⾼效。
Note that:新建类对象在创建该类型的数组时,为防⽌报错,需要给构造函数⾥的元素赋初值环形队列实现代码//队列模板实现.h⽂件#pragma once#include<iostream>using namespace std;template<class T>class Myqueue{public:Myqueue(int num);//构建队列⼤⼩void addIngre(T m);//增加元素void deleIngre();//删除元素int IngreNum();//返回当前队列元素个数bool queueFull();//判断满void clearIngre();//清空队列bool queueEmpty();//判空队列void queueTraverse();//遍历元素~Myqueue();//析构private:int m_iNum; //队列元素个数T* m_tArray;//数组int m_iHead;//头指针位置int m_iTail;//尾指针位置int m_iSize;//队列⼤⼩};template<class T>Myqueue<T>::Myqueue(int num){clearIngre();m_iSize = num;m_tArray = new T[m_iSize];}template<class T>Myqueue<T>::~Myqueue(){delete[]m_tArray;m_tArray = NULL;}template<class T>void Myqueue<T>::addIngre(T m)//增加元素{if (!queueFull()){m_iNum++;m_iTail = m_iTail % m_iSize;m_tArray[m_iTail] = m;m_iTail++;}else{cout << "Can not add any more ingredients!" << endl;}}template<class T>void Myqueue<T>::deleIngre()//⾸元素出队{if (!queueEmpty()){m_iNum--;cout <<"被消除的⾸元素为:"<< m_tArray[m_iHead] << endl;m_iHead++;m_iHead = m_iHead % m_iSize;}else{cout << "There is no ingredient!" << endl;}}template<class T>int Myqueue<T>::IngreNum()//返回当前队列元素个数{cout << "当前元素个数为:" <<m_iNum<< endl;return m_iNum;}template<class T>void Myqueue<T>::clearIngre(){m_iNum = 0;m_iTail = m_iHead = 0;cout << "当前元素个数为:" << m_iNum << endl;}//清空队列template<class T>bool Myqueue<T>::queueEmpty(){return m_iNum == 0 ? true : false;}//判空队列template<class T>bool Myqueue<T>::queueFull(){return m_iNum == m_iSize ? true : false;}//判断满template<class T>void Myqueue<T>::queueTraverse(){for (int i = m_iHead; i < m_iNum + m_iHead; i++){i = i % m_iSize;cout << m_tArray[i] << endl;}}//遍历元素//⾃定义类customer的.h⽂件#pragma once#include<iostream>using namespace std;#include<string>class customer{friend ostream& operator<<(ostream& out, customer& c)//<<重载只能⽤友元函数,因为与this指针⽆关{out << "Name:"<<<<","<<"Age:" << c.age;return out;//必须有返回值}public:customer(string n="陈胖⿅",int a=4);//为了防⽌⾃定义类在创建数组时报错,需要赋初值。
数据结构:队列的顺序存储结构(循环队列)队列的定义:队列是只允许在⼀端进⾏插⼊操作,⽽在另⼀端进⾏删除操作的线性表。
队列的抽象数据类型:ADT 队列(Queue)Data同线性表,元素具有相同的类型,相邻元素具有前驱和后继关系。
OperationInitQueue(*Q): 初始化操作,建⽴⼀个空队列。
DestroyQueue(*Q): 若队列Q存在,则销毁它。
ClearQueue(*Q): 将队列清空。
QueueEmpty(Q): 判断队列是否为空。
GetHead(Q,*e): 若队列存在且⾮空,⽤e返回Q的队头元素。
EnQueue(*Q,e): 若队列Q存在,插⼊新元素e到队列Q中并成为队尾元素。
DeQueue(*Q,*e): 删除队列中的队头元素,并⽤e返回。
QueueLength(Q): 返回队列Q的元素的个数。
endADT线性表有顺序存储和链式存储,栈是线性表,所以有这两种存储⽅式,有顺序栈和链栈。
同样队列作为⼀种特殊的线性表,也存在这两种存储⽅式。
先来看队列的顺序存储结构。
队列的顺序存储结构同线性表的顺序存储结构存在着同样的问题,队头出队列要后⾯的元素依次向前移动,时间复杂度为O(n)。
因为队列的每次删除元素都是从队头,所以每次删除都有⼤量的元素要移动,这样算法的效率很不好。
于是改进⼀下,队头不⼀定要在数组的下标为0的位置。
也就是说删除⼀个元素,仅需要把队头指针向后移动⼀次。
同时让front指针指向队头元素,rear指针指向队尾元素的下⼀个位置。
这样当front等于rear时,队列就为空。
但是此时还有问题,会有假溢出的现象。
解决这种问题的办法就是循环队列。
让上⾯的队尾指针rear指向数组的下标0位置。
队列的这种头尾相接的顺序存储结构称为循环队列。
但是还存在⼀个问题:当队列空或者满的时候都是front==rear。
那么这个要怎么判断呢?(1)设置⼀个标志变量flag,当fron==rear且flag==0时,队列为空;当front==rear且flag==1时队列满。
数据结构循环队列(基本操作及图⽰)————————————————————————————————————————————如果使⽤顺序表作为队列的话,当处于右图状态则不能继续插⼊新的队尾元素,否则会因为数组越界⽽导致程序代码被破坏。
由此产⽣了由链表实现的循环队列,只有队列未满时才可以插⼊新的队尾元素。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -基本操作:/* 定义链表队列 */定义结构体中front指⽰队头位置,rear指⽰队尾位置,base指针⽤于申请空间并存放数据。
/* 初始化队列 */使⽤指针*base申请100个内存空间,front和rear分别为0,此时队列为空/* 判断空或满 */初始化时,front = rear = 0 时为空,Q->rear = (0+1)%100 = 1,队列未满可以插⼊队列⼊队3个元素时,rear = 3,Q->rear = (3+1)%100 = 4,队列未满⼊队99个元素时,rear = 99,Q->rear = (99+1)%100 = 0,队列满,不可⼊队出队2个元素时,front = 2出队后,执⾏两次 Q->front = (Q->front + 1) % MAXQSIZE,得到Q->front = 2再次⼊队1个元素时,rear = 0,Q->rear = (99+1)%100=0,队列未满,可以⼊队实现代码:1 #include <stdio.h>2 #include <stdlib.h>3#define OK 14#define ERROR 05#define OVERFLOW -26#define MAXQSIZE 1007 typedef int Status;8 typedef int QElemType;9 typedef struct Node10 {11 QElemType *base; //初始化动态分配存储空间12int front;13int rear;14 } SqQueue;15 Status InitQueue(SqQueue *Q)16 {17 Q->base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType));18if (!Q->base)19 exit(OVERFLOW);20 Q->front = Q->rear = 0;21return OK;22 }23 Status EnQueue(SqQueue *Q, QElemType elem)24 {25//队列为空时 1%100==1,队列满时(99+1)%100==0,最多容纳99个元素26if ((Q->rear + 1) % MAXQSIZE == (Q->front))27return ERROR;28 Q->base[Q->rear] = elem;29 Q->rear = (Q->rear + 1) % MAXQSIZE; //rear始终在0-100中循环30return OK;31 }32 Status OutQueue(SqQueue *Q, QElemType *e)33 {34if (Q->front == Q->rear)35return ERROR;36 *e = Q->base[Q->front];37 Q->front = (Q->front + 1) % MAXQSIZE; 38return OK;39 }40 Status PrintQueue(SqQueue Q)41 {42 printf("the queue is:");43for (int i = Q.front; i < Q.rear; ++i)44 printf("%d ", Q.base[i]);45return OK;46 }47int main()48 {49 SqQueue queue;50 QElemType elem;51int i;52 InitQueue(&queue);53 printf("input:");54while(scanf("%d", &elem) != EOF)55 EnQueue(&queue, elem);56 PrintQueue(queue);57/* 输⼊要出队列的个数 */58 printf("\noutput:");59 scanf("%d", &i);60while(i != 0)61 {62 OutQueue(&queue, &elem);63 i--;64 }65 PrintQueue(queue);66return OK;67 }。
环形队列在处理⽹络分包,包未收完整时,必定需要⼀个缓冲区来缓存数据,ring_buffer是最常⽤的选择。
它是⼀个⽐较简单的数据结构,在学《数据结构》时想必⼤家都实现过,但我前⼏天就被它教育了⼀把,write时,⼀处分⽀漏了个等号,些许情况下会缓冲区溢出,导致堆栈⼀些数据被破坏,让我⾜⾜花了⼀整天才找到这个bug,我错误的地⽅如下:1int2 rbuf_write(struct ring_buffer *self,const char *data,int n){3 assert(self);4 assert(data);5if(n <= 0){6return0;7 }8for(;;){9 unsigned int len = rbuf_length(self) + n;10if(len >= INT_MAX){11return -1;12 }13if(self->cap - rbuf_length(self) -1 < n){14 rbuf__expand(self);15 }16else{17//少了等号18if(self->tail >self->head){19int copy1 = self->cap - self->tail;20if(copy1 > n ){21 copy1 = n;22 }23 memcpy(self->buf + self->tail,data,copy1);24if(copy1 < n){25 memcpy(self->buf,data + copy1,n - copy1);26 }27 }28else{29 memcpy(self->buf + self->tail,data,n);30 }31 self->tail = (self->tail + n ) % self->cap;32return n;33 }34 }35 }第18⾏的判断应该是>=,否则当n>(self->cap - self->tail)就会溢出。
数据结构实现循环队列的两种⽅法⼀、包含队列元素nItem⽅式:1package data.struct.algorithm;234//定义队列,包含五个域值5class Queuex {6private int maxSize;7private int[] queueArray;8private int front;9private int rear;10private int nItem;1112public Queuex(int s) {13 maxSize = s;14 queueArray = new int[maxSize];15 front = 0;16 rear = -1;17 nItem = 0;18 }1920//队列尾部插⼊元素21public void insert(int value) {22if(nItem==maxSize){23throw new RuntimeException("队列满了,不能插⼊数据了");24 }25if (rear == maxSize - 1) {26 rear = -1;27 }28 queueArray[++rear] = value;29 nItem++;30 }3132//队头删除元素33public int remove() {34if(nItem==0){35throw new RuntimeException("队列中没有元素了,不能进⾏删除操作了");36 }37int value = queueArray[front++];38if (front == maxSize) {39 front = 0;40 }41 nItem--;42return value;43 }4445//查看队头元素46public int peek() {47return queueArray[front];48 }4950//判断队列是否为空51public boolean isEmpty() {52return nItem == 0;53 }5455//判断队满56public boolean isFull() {57return nItem == maxSize;58 }5960//获取队列⼤⼩61public int getSize() {62return nItem;63 }64 }6566public class QueueApp {6768/**69 * @param args70*/71public static void main(String[] args) {7273 Queuex theQueue=new Queuex(10);74 theQueue.insert(3);75 theQueue.insert(13);76 theQueue.insert(23);77 theQueue.insert(33);78 theQueue.insert(43);79 theQueue.insert(53);80 System.out.println(theQueue.peek());81 System.out.println(theQueue.remove());82 theQueue.insert(63);83 theQueue.insert(73);84 theQueue.insert(83);85 theQueue.insert(93);86// theQueue.insert(103);87 System.out.println(theQueue.peek());88while(!theQueue.isEmpty()){89 System.out.print(theQueue.remove()+" ");90 }91 System.out.println();9293 }9495 }⼆、不包含队列元素nItem⽅式:1package data.struct.algorithm;23//定义队列,包含四个域值,不包含队列⼤⼩nItems4//判断队空:rear==front5//判断队空:(rear+1)%maxSize==front,即队头指针在队尾指针的下⼀个位置6class Queuey {7private int maxSize;8private int[] queueArray;9private int front;10private int rear;1112public Queuey(int s) {13 maxSize = s;14 queueArray = new int[maxSize];15 front = 0;16 rear = 0;17 }1819// 队列尾部插⼊元素20public void insert(int value) {21if (this.isFull()) {22throw new RuntimeException("队满");23 }24 queueArray[rear] = value;25 rear=(rear+1)%maxSize;26 }2728// 队头删除元素29public int remove() {30if (this.isEmpty()) {31throw new RuntimeException("队列中没有元素了,不能进⾏删除操作了");32 }33int value = queueArray[front];34 front = (front + 1) % maxSize;35return value;36 }3738// 查看队头元素39public int peek() {40return queueArray[front];41 }4243// 判断队列是否为空44public boolean isEmpty() {45return rear == front;46 }4748// 判断队满49public boolean isFull() {50return (rear + 1) % maxSize == front;51 }5253// 获取队列⼤⼩54public int getSize() {55return (rear - front + maxSize) % maxSize;56 }57 }5859public class CopyOfQueueApp {6061/**62 * @param args63*/64public static void main(String[] args) {6566 Queuey theQueue = new Queuey(5);67 theQueue.insert(13);68 theQueue.insert(23);69 theQueue.insert(33);70 theQueue.insert(43);71// theQueue.insert(63);72 System.out.println(theQueue.getSize());73 System.out.println(theQueue.remove());74 System.out.println(theQueue.remove());75 theQueue.insert(63);76 theQueue.insert(73);77 System.out.println(theQueue.peek());78while (!theQueue.isEmpty()) {79 System.out.print(theQueue.remove() + " ");80 }81 System.out.println();8283 }8485 }三、⽤链表来实现队列存放结点:1public class Node {23public int data;4public Node next;5public Node(int data,Node next){6this.data=data;7this.next=next;8 }9 }定义的链表的操作:1public class LinkList {23private Node head;4private Node tail;5public LinkList(){6 head=null;7 tail=null;8 }9public void insertLast(int data){10 Node newNode=new Node(data, null);11if(isEmpty()){12 head=newNode;13 }14else {15 tail.next=newNode;16 }17 tail=newNode;18 }19public int deleteHead(){20if(head.next==null){21 tail=null;22return head.data;23 }24if(head!=null){2526 Node tempNode=head;27 head=head.next;28return tempNode.data;29 }30else {31throw new RuntimeException("不能删除元素了");32 }33 }34public boolean isEmpty(){35return head==null;36 }3738 }链表模拟的队列1//⽤的是insertLast()和deleteHead()⽅法,即在尾部插⼊,在链表头删除 2public class LinkQueue {34private LinkList linkList;5public LinkQueue(){6 linkList=new LinkList();7 }8public void push(int data){9 linkList.insertLast(data);10 }11public int pop(){12return linkList.deleteHead();13 }14public boolean isEmpty(){15return linkList.isEmpty();16 }17 }测试类1public class QueuqTest {23/**4 * @param args5*/6public static void main(String[] args) {78 LinkQueue linkQueue=new LinkQueue();9 linkQueue.push(10);10 linkQueue.push(20);11 linkQueue.push(30);12 linkQueue.push(40);13 System.out.println(linkQueue.pop());14 }15 }。
实现环形队列的各种基本运算的算法一、引言环形队列是一种特殊的队列数据结构,它的特点是首尾相连,形成一个环形的结构。
在环形队列中,插入和删除操作可以在常数时间内完成,因此在实际应用中被广泛使用。
本文将介绍如何实现环形队列的各种基本运算的算法,包括初始化、入队、出队、判空、判满等操作。
二、初始化环形队列初始化环形队列需要创建一个固定大小的数组来存储队列中的元素,并设置头尾指针。
首先,我们需要定义一个变量n来表示队列的大小,然后创建一个大小为n的数组来存储元素。
接着,我们定义两个指针front和rear来分别指向队列的头部和尾部。
初始化时,我们将front和rear都设置为0,表示队列为空。
三、入队操作入队操作将一个元素插入到队列的尾部。
首先,我们需要判断队列是否已满,如果rear+1等于front,则表示队列已满,无法插入新元素。
否则,我们将新元素插入到rear所指向的位置,并将rear 指针后移一位。
如果rear已经指向了队列的末尾,我们需要将rear 重置为0,以实现环形结构。
四、出队操作出队操作将队列头部的元素删除,并将头部指针front后移一位。
首先,我们需要判断队列是否为空,如果front等于rear,则表示队列为空,无法进行出队操作。
否则,我们将front指针后移一位,并返回front指针所指向的元素。
如果front已经指向了队列的末尾,我们需要将front重置为0,以实现环形结构。
五、判空操作判空操作用于判断队列是否为空。
如果front等于rear,则表示队列为空,否则队列不为空。
六、判满操作判满操作用于判断队列是否已满。
如果rear+1等于front,则表示队列已满,否则队列未满。
七、算法实现下面是环形队列的算法实现:1. 初始化环形队列- 定义变量n表示队列大小- 创建大小为n的数组queue- 定义指针front和rear,并将它们都初始化为02. 入队操作- 判断队列是否已满- 如果队列已满,则返回错误信息- 否则,将新元素插入到rear所指向的位置- 将rear后移一位,并判断rear是否已经到达队列末尾,如果是则将rear重置为03. 出队操作- 判断队列是否为空- 如果队列为空,则返回错误信息- 否则,将front后移一位,并返回front指向的元素- 判断front是否已经到达队列末尾,如果是则将front重置为04. 判空操作- 如果front等于rear,则返回true,表示队列为空- 否则,返回false,表示队列不为空5. 判满操作- 如果rear+1等于front,则返回true,表示队列已满- 否则,返回false,表示队列未满八、总结本文介绍了如何实现环形队列的各种基本运算的算法,包括初始化、入队、出队、判空、判满等操作。
数据结构:循环队列(C语言实现)生活中有很多队列的影子,比如打饭排队,买火车票排队问题等,可以说与时间相关的问题,一般都会涉及到队列问题;从生活中,可以抽象出队列的概念,队列就是一个能够实现“先进先出”的存储结构。
队列分为链式队列和静态队列;静态队列一般用数组来实现,但此时的队列必须是循环队列,否则会造成巨大的内存浪费;链式队列是用链表来实现队列的。
这里讲的是循环队列,首先我们必须明白下面几个问题一、循环队列的基础知识1.循环队列需要几个参数来确定循环队列需要2个参数,front和rear2.循环队列各个参数的含义(1)队列初始化时,front和rear值都为零;(2)当队列不为空时,front指向队列的第一个元素,rear指向队列最后一个元素的下一个位置;(3)当队列为空时,front与rear的值相等,但不一定为零;3.循环队列入队的伪算法(1)把值存在rear所在的位置;(2)rear=(rear+1)%maxsize ,其中maxsize代表数组的长度;程序代码:[cpp]view plaincopy1.bool Enqueue(PQUEUE Q, int val)2.{3.if(FullQueue(Q))4.return false;5.else6. {7. Q->pBase[Q->rear]=val;8. Q->rear=(Q->rear+1)%Q->maxsize;9.return true;10. }11.}4.循环队列出队的伪算法(1)先保存出队的值;(2)front=(front+1)%maxsize ,其中maxsize代表数组的长度;程序代码:[cpp]view plaincopy1.bool Dequeue(PQUEUE Q, int *val)2.{3.if(EmptyQueue(Q))4. {5.return false;6. }7.else8. {9. *val=Q->pBase[Q->front];10. Q->front=(Q->front+1)%Q->maxsize;11.return true;12. }13.}5.如何判断循环队列是否为空if(front==rear)队列空;else队列不空;[cpp]view plaincopy1.bool EmptyQueue(PQUEUE Q)2.{3.if(Q->front==Q->rear) //判断是否为空4.return true;5.else6.return false;7.}6.如何判断循环队列是否为满这个问题比较复杂,假设数组的存数空间为7,此时已经存放1,a,5,7,22,90六个元素了,如果在往数组中添加一个元素,则rear=front;此时,队列满与队列空的判断条件front=rear相同,这样的话我们就不能判断队列到底是空还是满了;解决这个问题有两个办法:一是增加一个参数,用来记录数组中当前元素的个数;第二个办法是,少用一个存储空间,也就是数组的最后一个存数空间不用,当(rear+1)%maxsiz=front时,队列满;[cpp]view plaincopy1.bool FullQueue(PQUEUE Q)2.{3.if(Q->front==(Q->rear+1)%Q->maxsize) //判断循环链表是否满,留一个预留空间不用4.return true;5.else6.return false;7.}附录:queue.h文件代码:[cpp]view plaincopy1.#ifndef __QUEUE_H_2.#define __QUEUE_H_3.typedef struct queue4.{5.int *pBase;6.int front; //指向队列第一个元素7.int rear; //指向队列最后一个元素的下一个元素8.int maxsize; //循环队列的最大存储空间9.}QUEUE,*PQUEUE;10.11.void CreateQueue(PQUEUE Q,int maxsize);12.void TraverseQueue(PQUEUE Q);13.bool FullQueue(PQUEUE Q);14.bool EmptyQueue(PQUEUE Q);15.bool Enqueue(PQUEUE Q, int val);16.bool Dequeue(PQUEUE Q, int *val);17.#endifqueue.c文件代码:[cpp]view plaincopy1.#include<stdio.h>2.#include<stdlib.h>3.#include"malloc.h"4.#include"queue.h"5./***********************************************6.Function: Create a empty stack;7.************************************************/8.void CreateQueue(PQUEUE Q,int maxsize)9.{10. Q->pBase=(int *)malloc(sizeof(int)*maxsize);11.if(NULL==Q->pBase)12. {13. printf("Memory allocation failure");14. exit(-1); //退出程序15. }16. Q->front=0; //初始化参数17. Q->rear=0;18. Q->maxsize=maxsize;19.}20./***********************************************21.Function: Print the stack element;22.************************************************/23.void TraverseQueue(PQUEUE Q)24.{25.int i=Q->front;26. printf("队中的元素是:\n");27.while(i%Q->maxsize!=Q->rear)28. {29. printf("%d ",Q->pBase[i]);30. i++;31. }32. printf("\n");33.}34.bool FullQueue(PQUEUE Q)35.{36.if(Q->front==(Q->rear+1)%Q->maxsize) //判断循环链表是否满,留一个预留空间不用37.return true;38.else39.return false;40.}41.bool EmptyQueue(PQUEUE Q)42.{43.if(Q->front==Q->rear) //判断是否为空44.return true;45.else46.return false;47.}48.bool Enqueue(PQUEUE Q, int val)49.{50.if(FullQueue(Q))51.return false;52.else53. {54. Q->pBase[Q->rear]=val;55. Q->rear=(Q->rear+1)%Q->maxsize;56.return true;57. }58.}59.60.bool Dequeue(PQUEUE Q, int *val)61.{62.if(EmptyQueue(Q))63. {64.return false;65. }66.else67. {68. *val=Q->pBase[Q->front];69. Q->front=(Q->front+1)%Q->maxsize;70.return true;71. }72.}[文档可能无法思考全面,请浏览后下载,另外祝您生活愉快,工作顺利,万事如意!]。
数据结构与算法——队列(环形队列)⽬录⼀个使⽤场景银⾏办理业务的排队叫号办理业务的⼈先拿号,然后窗⼝叫号处理,没有叫到的,则排队等待。
基本介绍队列:是⼀个有序列表,可以⽤数组或链表实现。
特点:遵循先⼊先出原则。
即:先存⼊的数据,先取出。
⽰意图:front:队⾸,队列头部rear:队尾,队列尾部左 1 图:队列初始化的两个变量值中图:存⼊数据后,的⾸位变化右图:取数据时,从队⾸取,队⾸的变量指向也在发⽣变化数组模拟队列队列本⾝是有序列表,使⽤数组结构来存储队列的数据,则如前⾯基本介绍中的⽰意图⼀样。
声明 4 个变量:arr:⽤来存储数据的数组maxSize:该队列的最⼤容量front:队⾸下标,随着数据输出⽽改变rear:队尾下标,随着数据输⼊⽽改变队列中常⽤操作分析,以 add,把数据存⼊队列为例,思路分析:1. 将尾指针往后移:rear + 1,前提是当front == rear时,队列是空的2. 若尾指针 rear < maxSize -1:则将数据存⼊ rear 所指的数组元素中,否则⽆法存⼊数据。
rear = maxSize -1 表⽰队列满了以上思路是⼀个最基本的实现(不是完美的,看完代码就明⽩了)。
代码实现如下* 数组模拟队列*/public class ArrayQueueDemo {public static void main(String[] args) {ArrayQueue queue = new ArrayQueue(3);queue.add(1);queue.add(2);queue.add(3);System.out.println("查看队列中的数据");queue.show();System.out.println("查看队列头数据:" + queue.head());System.out.println("查看队列尾数据:" + queue.tail());// queue.add(4);System.out.println("获取队列数据:" + queue.get());System.out.println("查看队列中的数据");queue.show();}}class ArrayQueue {private int maxSize; // 队列最⼤容量private int front; // 队列头,指向队列头的前⼀个位置private int rear; // 队列尾,指向队列尾的数据(及最后⼀个数据) private int arr[]; // ⽤于存储数据,模拟队列public ArrayQueue(int arrMaxSize) {maxSize = arrMaxSize;arr = new int[maxSize];front = -1;rear = -1;}/*** 取出队列数据*/public int get() {if (isEmpty()) {throw new RuntimeException("队列空");}return arr[++front];}/*** 往队列存储数据*/public void add(int n) {if (isFull()) {System.out.println("队列已满");return;}arr[++rear] = n;}/*** 显⽰队列中的数据*/public void show() {if (isEmpty()) {System.out.println("队列为空");return;}for (int i = 0; i < arr.length; i++) {System.out.printf("arr[%d] = %d \n", i, arr[i]);}}/*** 查看队列的头部数据,注意:不是取出数据,只是查看** @return*/public int head() {if (isEmpty()) {throw new RuntimeException("队列空");}return arr[front + 1]; // front 指向队列头前⼀个元素,取头要 +1 }/*** 查看队尾数据** @return*/public int tail() {if (isEmpty()) {throw new RuntimeException("队列空");}return arr[rear];}// 队列是否已满private boolean isFull() {return rear == maxSize - 1;}// 队列是否为空private boolean isEmpty() {return rear == front;}运⾏测试查看队列中的数据arr[0] = 1arr[1] = 2arr[2] = 3查看队列头数据:1查看队列尾数据:3获取队列数据:1查看队列中的数据arr[0] = 1arr[1] = 2arr[2] = 3分析⽬前实现了⼀个⼀次性的队列(不能复⽤),因为可以往队列中添加数据,基本功能也是可以的,当队列满之后,再添加就加不进去了,获取数据也不能清空原队列中的数据。
c语言数据结构(环形队列)环形队列是一种经典的数据结构,它在很多场景中发挥着重要的作用。
本文将介绍C语言中的环形队列的原理、实现及其在实际应用中的一些注意事项。
1.环形队列的原理环形队列是一种特殊的队列,它的底层数据结构是一个数组。
与普通队列不同的是,当队列的尾指针指向数组的最后一个位置时,如果还需要继续插入元素,尾指针则跳转到数组的第一个位置。
这样就形成了一个环形的结构,可以循环利用数组中的空间。
2.环形队列的实现环形队列的实现主要涉及到以下几个要素:-队列的初始化:需要给队列分配一块固定大小的内存空间,并初始化队列的头指针和尾指针。
-入队操作:将元素插入到队列的尾部,并更新尾指针的位置。
-出队操作:将队列头部的元素移除,并更新头指针的位置。
-判空操作:判断队列是否为空,即头指针和尾指针是否相等。
-判满操作:判断队列是否已满,即尾指针的下一个位置是否等于头指针。
以下是一个基于数组的环形队列的简单实现:```c#define MAX_SIZE 100typedef structint data[MAX_SIZE];int front; // 头指针int rear; // 尾指针} CircularQueue;void initQueue(CircularQueue *queue)queue->front = 0;queue->rear = 0;void enqueue(CircularQueue *queue, int element)if ((queue->rear + 1) % MAX_SIZE == queue->front) printf("Queue is full.\n");return;}queue->data[queue->rear] = element;queue->rear = (queue->rear + 1) % MAX_SIZE;int dequeue(CircularQueue *queue)if (queue->front == queue->rear)printf("Queue is empty.\n");return -1;}int element = queue->data[queue->front];queue->front = (queue->front + 1) % MAX_SIZE;return element;int isEmpty(CircularQueue *queue)return queue->front == queue->rear;int isFull(CircularQueue *queue)return (queue->rear + 1) % MAX_SIZE == queue->front;```3.环形队列的应用注意事项在使用环形队列时,需要注意以下几点:-队列的大小是有限制的,如果插入元素的速度过快,可能会导致队列溢出。
环形队列的工作原理嘿,朋友!你有没有想过一种超级有趣又超级实用的数据结构呀?今天我就想和你唠唠环形队列。
环形队列就像是一个特别的环形跑道,不过在这个跑道上跑的不是运动员,而是数据。
想象一下,你有一群小伙伴,他们要按照顺序做一件事情,但是场地有限,不能无限制地排很长的队伍,这个环形队列就像是这个特殊的场地。
我们先来说说环形队列的基本组成部分吧。
它有一个数组,这个数组就好比是那个环形跑道的轮廓。
数组有固定的大小,这就像是跑道的长度是固定的一样。
然后呢,还有两个指针,这两个指针可太重要了,就像是跑道上的两个小指挥。
一个指针叫头指针,它指向队列的头部,就像站在跑道起点指挥的人,告诉大家从这儿开始。
另一个指针是尾指针,它指向队列的尾部,就像在跑道最后面确认大家都跑到哪儿的人。
那这个环形队列是怎么工作的呢?当我们要往队列里添加数据的时候,就像是小伙伴们要进入这个特殊的场地。
尾指针就开始发挥作用了。
它会找到下一个可以存放数据的位置,然后把数据放进去。
这就好像是小伙伴们按照顺序站在跑道上一样。
如果尾指针走到了数组的末尾,嘿,这时候神奇的事情发生了,它不会就停在那儿,而是像在环形跑道上一样,又回到数组的开头继续找位置。
这多酷啊!再说说取出数据呢。
这时候头指针就上场了。
它会指向要取出的数据的位置,然后把数据取出来。
取完之后,头指针也会像尾指针一样,如果到了数组的末尾,就又回到开头。
这就好比小伙伴们完成了任务,从起点离开,下一个小伙伴又从新的起点开始自己的任务。
我给你举个小例子吧。
假设有个环形队列用来处理顾客的订单。
这个环形队列的数组大小是10。
有个店员小李,他负责把新的订单放进队列,这就相当于尾指针的操作。
另一个店员小张,他负责处理订单,这就是头指针的操作。
一开始,队列是空的,小李接到了3个订单,他就把这3个订单依次放进队列,尾指针也跟着往后移动。
这时候小张开始处理订单,他从队列头部取订单,每取一个订单,头指针就移动一下。
环形队列用法环形队列是一种特殊的队列数据结构,它与普通队列的不同之处在于,当队列的尾部指针已经达到数组的末尾时,还可以继续循环到数组的开头,使得队列可以在有限的存储空间中实现无限的循环。
使用环形队列可以最大限度地利用存储空间,避免了出现溢出的情况。
环形队列的用法主要包括以下几个方面:1. 初始化环形队列:创建一个固定大小的数组作为环形队列的底层数据结构,并初始化队列的头部和尾部指针。
2. 入队操作:将一个元素添加到队列的尾部,并更新尾指针。
当队列已满时,无法继续添加元素。
3. 出队操作:从队列的头部删除一个元素,并更新头指针。
当队列为空时,无法进行出队操作。
4. 判空操作:检查队列是否为空,即头指针是否等于尾指针。
5. 判满操作:检查队列是否已满,即尾指针达到数组末尾时下一个位置是否为头指针。
6. 获取队列长度:计算队列中元素的个数,即尾指针减去头指针的绝对值,再加上1。
7. 清空队列:将头指针和尾指针重置为初始状态。
通过以上的操作,可以实现对环形队列的基本管理和利用。
示例代码(使用Python语言):```pythonclass CircularQueue:def __init__(self, capacity):self.capacity = capacityself.queue = [None] * capacityself.head = 0self.tail = 0def enqueue(self, item):if self.is_full():raise Exception("Queue is full")self.queue[self.tail] = itemself.tail = (self.tail + 1) % self.capacitydef dequeue(self):if self.is_empty():raise Exception("Queue is empty")item = self.queue[self.head]self.head = (self.head + 1) % self.capacityreturn itemdef is_empty(self):return self.head == self.taildef is_full(self):return (self.tail + 1) % self.capacity == self.headdef get_length(self):return (self.tail - self.head + self.capacity) % self.capacitydef clear(self):self.head = 0self.tail = 0self.queue = [None] * self.capacity```以上是一个简单的环形队列的实现,包括了入队、出队、判空、判满、获取队列长度和清空队列等操作。