队列性能明智哪个是更好的实现 - 数组或链表

2024-02-12

当我必须插入很少的元素时,哪种方式可以更快地入队和出队,数组比链表更好吗?

我需要插入一些元素,并且必须从队列中删除并读取该删除的元素。 如果它是数组,每次删除元素时我可能都必须修改索引。插入和删除也可能同时发生。

从下面的案例来看,哪一个更好呢?

typedef struct{
    mylist list;
    struct mylistQ *next;
}mylistQ;

数组代码

 static mylist myListQ[QUEUESIZE+1];
int qLast = 0;

void enqueue_element(mylist qItem)
{
        myListQ[qLast] = qItem;
    qLast++;
}

mylist dequeue_element()
{
 retryq:
   if(qLast >0) {
    mylist qReturn = myListQ[0];  
    int i;
    for (i = 0; i < qLast - 1; i++){
        myListQ[i] = myListQ[i + 1];
    }
    qLast--; 
    return qReturn;
     }
   else {
    goto retryq;
    }
}

链表

 int qLast = 0;

mylistQ *headElement = NULL;   
mylistQ *tailElement = NULL;     

void enqueue_element(mylist *List)
{
    mylistQ *newnode;      
    newnode=(mylistQ*)av_malloc(sizeof(mylistQ));
    newnode->next=NULL;
    newnode->list=*List;
    qLast++;
    if(headElement==NULL && tailElement==NULL)
    {
        headElement=newnode;
        tailElement=newnode;
    }
    else
    {
        tailElement->next=newnode;
        tailElement=newnode;
    }
 }

mylist dequeue_element()
{
    mylistQ *delnode;      /* Node to be deleted */
    mylist Dellist;
    if(headElement==NULL && tailElement==NULL){
        LOg( "Queue is empty to delete any element");
        }
    else
    {
       Log("In dequeue_picture queue is not empty");
        delnode=headElement;
        headElement=headElement->next;
    if (!headElement){
        tailElement=NULL;
    }
        Dellist = delnode->list;
        av_free(delnode);
    qLast--;
    }
        return Dellist;
}

这取决于您将执行多少操作以及数组版本的具体实现方式。

如果您执行的操作相对较少,即总共少于 1000 次左右入队/出队,那么数组会更快,因为它在内存中是连续的。维护一个指向前面的指针和一个指向后面的指针,总是在后面添加,在前面出列。

另一方面,即使列表不超过 30 个左右的元素,如果这种情况必须持续很长一段时间,您也不会有任何数组大小调整问题,这是数组的潜在问题。

链接列表保证了出色的性能,您必须注意数组的大小调整。

编辑: 正如 @Hans Passant 所提到的,数组速度很快,因为它们具有 CPU 缓存局部性。只要您的阵列很小,您的硬件就会优化性能,以便与存储阵列相关的内存将保留在 L2 中。索引可能在寄存器中。这真的很快。从您不需要很多元素的事实来看,在这种情况下数组是理想的选择。是的,当您移动元素时,您必须修改索引,但这实际上是一个非常快的操作,因为如果您通过优化构建代码,索引将存储在注册器中。

不过,这里有一个问题,您提到您可能必须同时进行入队和出队,这是否意味着它是并行的,即多个线程访问内存?如果是这种情况,数组仍然会更快,但您会看到性能下降了 800 倍左右。为什么?因为处理器不再可以缓冲与芯片上的队列相关的内存,但它必须存储在主内存中。此外,您还面临着在线程之间创建竞争条件的风险。想象一下,如果一个线程尝试出队,而另一个线程尝试入队,并且列表中只有一个元素,那么您可能会遇到灾难。无论哪种方式,如果此应用程序非常注重性能,请务必在打开 NDEBUG 和 -O3 标志的情况下进行编译(假设是 gcc)。

第二次编辑: 查看代码,并查看下面的其他答案,我建议使您的数组代码更高效并将其转换为圆形数组,因为听起来您对元素数量有上限。附带说明一下,当前的数组实现效率极低,每次删除时都会向前复制队列的其余部分,这没有意义,只需增加一个指向“第一个”索引的 int 指针即可。

伪代码:

int ciruclarArray[SIZE];
int front = 0;
int back = 0;

void enqueue(int elem)
{
    circularArray[back] = elem;
    if(back < (circularArray.length - 1))
        back++;
    else
        back = 0;
    return elem;
}

int dequeue()
{
    int toReturn = circularArray[front];
    //do same check for incrementing as enqueue
    return toReturn;
}

只是不要忘记对正常的东西进行错误检查。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

队列性能明智哪个是更好的实现 - 数组或链表 的相关文章

随机推荐

  • 如何使 C# 命名空间像 Java 包一样工作,以便在移动它们时自动重命名?

    我来自Java 发现Java中的包非常方便 当您将一个类移动到另一个包时 它会自动更改该包 当然 可以通过 Eclipse 或 Netbean 等 IDE 但 C 使用命名空间 并且不会像 Java 那样自动重命名我的命名空间 例如我有一个
  • 纯C 中的Cocoa OpenGL 窗口?

    我想在 MacOSX 中打开一个 OpenGL 窗口 以显示和抓取击键 鼠标事件 我不想使用 Glut 因为它要求它是根线程 我不想学习 Objective C 有没有办法用纯C语言访问OpenGL api Thanks 如果您想在 OS
  • 如何查看我的 GitHub 拉取请求已被接受的数量?

    有没有办法查明 GitHub PR 的接受率 可能使用 API 与此同时 了解所有存储库中我报告的问题有多少已经关闭以及仍然开放 这将是很有趣的 您还可以使用GraphQL API v4 https developer github com
  • 无法更新生产服务器上的 gem

    无法更新生产服务器上的 gem 我试过了bundle install deployment and bundle install without development test 但继续得到 You are trying to instal
  • 如果使用 CGPointEqualToPoint 不起作用

    我试图找出为什么当球位置与块位置完全相同并且锚点相同时该函数不执行 GameEnd 函数 if CGPointEqualToPoint ball position block position if CGPointEqualToPoint
  • 如何在socket.io中删除房间

    我想静态地从房间中删除所有用户 从而有效地删除该房间 这个想法是 将来可能会再次创建另一个同名的房间 但我希望它创建为空 没有前一个房间的听众 我对自己管理房间状态不感兴趣 而是很好奇 好像我可以利用 socket io 内部结构来做到这一
  • 在 iPhone 上创建弹出窗口?

    我想在 iPhone 上创建一个自定义样式的弹出框 我希望它有一个向上的箭头 关于如何实现这一目标有什么想法吗 尝试这个FP 弹出窗口 https github com 50pixels FPPopover它会对你有所帮助
  • 如何使用rails控制台进行调试并放入应用程序

    我想在通过 Rails 控制台打开的 irb 中打印一些行 我见过很多关于如何实现它的问题 但我在 irb 中什么也没得到 下面是代码 def show puts in show method post Feed find by id pa
  • 如何同时使用 CGAffineTransformMakeScale 和 Rotation?

    UIImageView dsry objectAtIndex 0 transform CGAffineTransformMakeRotation 1 57 2 UIImageView dsry objectAtIndex 0 transfo
  • 最喜欢的内容未在 webview 上正确显示

    我正在开发一个语言词典应用程序 我将最喜欢的单词保存到首选项中 XML 文件中的收藏夹内容如下所示
  • 伪代码的标准? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我需要将一些 python 和 java 例程翻译成我的硕士论文的伪代码 但在想出语法 风格时遇到了困难 持续的 容易明白 不太详细 不太接近自
  • 嵌入随机命名的 MP3

    这是我的代码 我希望 mp3 的 src 考虑到存在许多随机命名的 mp3 文件 sound 目录 并在每次打开页面时随机选择一个 有什么线索给我吗 我的服务器启用了 PHP 但我想让它尽可能简单 这应该可以做到 files glob pa
  • Android 通知上的表情符号

    我正在尝试在通知栏上显示表情符号 这是我的字符串 ue057 getString R string notification sent hey 我已经尝试过使用 Softbank 以及每种可能的格式 U 1F601 xF0 x9F x98
  • 在 Windows 上的 VSCode 中调试 Python C/C++ 扩展

    问题总结 我正在为 Python 开发一个自 C 扩展 以提高特定代码段的性能 我想调试这个扩展 但到目前为止还没有成功 我关注了几个链接 例如这是纳迪亚的 https nadiah org 2020 03 01 example debug
  • sklearn 维度问题“发现数组具有暗淡 3。预计估计器 <= 2”

    我正在尝试使用 KNN 将 wav 文件正确分类为两组 组 0 和组 1 我提取了数据 创建了模型 拟合了模型 但是当我尝试使用 predict 方法时 出现以下错误 Traceback most recent call last File
  • MAMP 与 Laravel Unix Socket

    我正在我的 laravel 应用程序的本地开发服务器上使用 MAMP 我试图弄清楚如何安全地设置我的服务器 这样我就不必在数据库连接 mysql 数组中使用以下内容 因为那应该只当我在我的开发服务器上时使用 当我将行添加到 mysql 数组
  • git merge 在cherry-pick之后如何工作?

    让我们想象一下我们有一个master branch 然后我们创建一个newbranch git checkout b newbranch 并做出两个新的承诺newbranch commit1 and commit2 然后我们切换到maste
  • GCC 中 -O0 和 -O1 的区别

    在编译一些代码时 我注意到 O0 和 O1 之间创建的汇编器存在很大差异 我想运行启用 禁用优化 直到找出导致汇编器发生某种变化的原因 如果我使用 fverbose asm 准确找出 O1 与 O0 相比启用了哪些标志 然后手动禁用它们 为
  • 如何删除输入日期的 x 和向上/向下箭头元素?

    我唯一需要在框中显示的是橙色三角形 并且我不确定是否需要 CSS 或其他内容来删除三角形左侧的两个元素 有办法这样做吗 我只是使用输入类型date Fiddle http jsfiddle net 5M2PD 1 http jsfiddle
  • 队列性能明智哪个是更好的实现 - 数组或链表

    当我必须插入很少的元素时 哪种方式可以更快地入队和出队 数组比链表更好吗 我需要插入一些元素 并且必须从队列中删除并读取该删除的元素 如果它是数组 每次删除元素时我可能都必须修改索引 插入和删除也可能同时发生 从下面的案例来看 哪一个更好呢