03920171126数据结构环形队列

合集下载

C#环形队列的实现方法详解

C#环形队列的实现方法详解

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来实现。

三、队列的实现队列可以通过不同的数据结构来实现,如数组、链表和循环列表等。

在这里,我们将介绍使用数组和链表来实现队列的基本操作。

使用数组实现队列使用数组实现队列时,我们需要保留一个空间来跟踪队列的开头和结尾。

通常,我们使用两个指针,一个指向队列的开头,另一个指向队列的结尾。

当我们在队列中添加一个新元素时,我们将它添加到结尾指针所指向的位置,并将结尾指针向后移动一位。

当我们要删除一个元素时,我们只需将开头指针向后移动一位并返回该位置的元素即可。

使用链表实现队列使用链表实现队列时,我们通常使用一个头指针指向队首元素,一个尾指针指向队尾元素的下一个位置。

入队操作时,我们在尾指针的位置创建一个新节点,并将尾指针移动到下一个位置。

出队操作时,我们只需删除头指针指向的节点,并将头指针移动到下一个位置。

四、队列的应用队列在计算机科学中有着广泛的应用,下面列举几个常见的例子:事件处理:在多线程编程中,队列经常用于事件驱动的系统来传递事件或消息。

环形队列实现原理 链式实现

环形队列实现原理 链式实现
PRINT_INT(data);
if(ringq_poll(p_queue, &data) >= 0)
PRINT_INT(data);
ringq_free(p_queue);
}
/*测试第一种环形队列,更加复杂的情况*/
void test6()
{
RINGQ rq, * p_queue;
int i, data;
出队操作:如果队列不空,则从head处读出。
下一个可读的位置在q->head = (q->head + 1) % q->size
头文件
ringq.h
#ifndef __RINGQ_H__
#define __RINGQ_H__
#ifdef __cplusplus
extern "C" {
#endif
#define RINGQ_MAX 20
ringq_push(p_queue, 5);
if(ringq_poll(p_queue, &data) >= 0)
PRINT_INT(data);
if(ringq_poll(p_queue, &data) >= 0)
PRINT_INT(data);
ringq_push(p_queue, 6);
if(ringq_poll(p_queue, &data) >= 0)
{
print_ringq(p_queue);
if(ringq_is_empty(p_queue))
{
printf("ringq is empty\n");
return -1;
}

【数据结构】C++语言无锁环形队列的实现

【数据结构】C++语言无锁环形队列的实现

【数据结构】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语言环形队列算法编写

c语言环形队列算法编写

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++代码

数据结构-环形队列-队列模板实现-c++代码

数据结构-环形队列-队列模板实现-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时队列满。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档