链式队列和顺序队列

本文介绍了两种队列数据结构的实现方法:一种是使用顺序表实现循环队列;另一种是采用链表实现链式队列。通过具体代码展示了队列的基本操作,包括入队、出队、获取队首元素等。

首先来看一下百度百科关于队列的介绍:

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

队列满足先进先出(FIFO)的原则,我们可以用链表的尾插头删模拟队列,还可以用顺序表实现循环队列。
下面介绍一下循环栈:
这里写图片描述

seqqueue.h

#include<stdio.h>
#include<stddef.h>

#define TestType printf("\n###################### %s #########################\n",__FUNCTION__)

//设置最大数量 4,这样设置是为了在后面的测试中方便模拟达到最大元素的状态
#define SeqQueueMaxSize 4
typedef char SeqQueueType;
typedef struct SeqQueue{
    SeqQueueType data[SeqQueueMaxSize];
    size_t head;
    size_t tail;
    size_t size;
} SeqQueue;

//初始化函数
void SeqQueueInit(SeqQueue* q);
//入队列函数
void SeqQueuePush(SeqQueue* q,SeqQueueType value);
//出队列函数
void SeqQueuePop(SeqQueue* q);
//打印函数
void SeqQuquqPrint(SeqQueue* q,const char* msg);
//取对手元素
int SeqQueueFront(SeqQueue* q,SeqQueueType* value);

seqqueue.c

#include"seqqueue.h"

void SeqQueueInit(SeqQueue* q){
    if(q == NULL){
        return;
    }
    q->tail = 0;
    q->head = 0;
    q->size = 0;
    return;
}

void SeqQueuePush(SeqQueue* q,SeqQueueType value){
    if(q == NULL){
        return;
    }
    if(q->size >= SeqQueueMaxSize){
        return;
    }
    q->data[q->tail++] = value;
    if(q->tail >= SeqQueueMaxSize){
    //如果队列的tail号下标达到最大值,下一个元素在数组的0号元素插入
        q->tail = 0;
    }
    q->size++;
}

void SeqQueuePop(SeqQueue* q){
    if(q == NULL){
        return;
    }
    if(q->size == 0){
        return;
    }
    q->head++;
    if(q->head >= SeqQueueMaxSize){
        q->head = 0;
    }
    q->size--;
}
//打印函数
void SeqQuquqPrint(SeqQueue* q,const char* msg){
    if(q == NULL){
        return;
    }
    printf("[ %s ]:\n",msg);
    int i = q->tail - 1;
    int count = q->size - 1;
    打印tail开始的count个元素
    while(count--){
        if(i >= 0){
            printf("%c->",q->data[i--]);
        }else{
            i = SeqQueueMaxSize - 1;
            printf("%c->",q->data[i--]);
        }
    }
    printf("%c\n",q->data[q->head]);
    return;
}

//取队首元素,这里的value是输出型参数
int SeqQueueFront(SeqQueue* q,SeqQueueType* value){
    if(q == NULL){
        return 0;
    }
    if(q->size == 0){
        return 0;
    }
    *value = q->data[q->head];
    return 1;
}

main.c

#include"seqqueue.h"

void TestSeqQueuePush(){
    TestType;
    SeqQueue q;
    SeqQueueInit(&q);
    SeqQueuePush(&q,'a');
    SeqQueuePush(&q,'b');
    SeqQueuePush(&q,'c');
    SeqQueuePush(&q,'d');
   // SeqQueuePush(&q,'e');
    SeqQuquqPrint(&q,"abcde入队列");
    SeqQueuePop(&q);
    SeqQuquqPrint(&q,"a出队列");
    SeqQueuePop(&q);
    SeqQuquqPrint(&q,"b出队列");
    SeqQueuePush(&q,'e');
    SeqQuquqPrint(&q,"e入队列");
    return;
}

void TestSeqQueueFront(){
    TestType;
    SeqQueueType value;
    SeqQueue q;
    SeqQueueInit(&q);
    SeqQueuePush(&q,'a');
    SeqQueuePush(&q,'b');
    SeqQueuePush(&q,'c');
    SeqQueuePush(&q,'d');
    int ret = SeqQueueFront(&q,&value);
    printf("expect: 1 , actual:%d\n",ret);
    printf("expect: a , actual:%c\n",value);
    SeqQueuePop(&q);
    SeqQueuePop(&q);
    SeqQueuePush(&q,'e');
    SeqQuquqPrint(&q,"ab出队列,e入队列");
    ret = SeqQueueFront(&q,&value);
    printf("expect: 1 , actual:%d\n",ret);
    printf("expect: c , actual:%c\n",value);
    return;
}

int main(){
    TestSeqQueuePush();
    TestSeqQueueFront();
    return 0;
}

上面就是用顺序表模拟队列的实现过程。

下面来介绍一下,链式队列
linkqueue.c

#pragma once
#include<stdio.h>
#include<stddef.h>
#include<stdlib.h>

#define TestType printf("\n################################## %s #################################\n",__FUNCTION__)
#define LinkQueueType char

typedef struct LinkNode{
    struct LinkNode* next;
    LinkQueueType data;
} LinkNode;

typedef struct LinkQueue{
    struct LinkNode* head;
    struct LinkNode* tail;
} LinkQueue;
//初始化函数
void LinkQueueInit(LinkQueue* q);
//入队列函数
void LinkQueuePush(LinkQueue* q,LinkQueueType value);
//打印函数
void LinkQueuePrint(LinkQueue* q,const char* msg);
//出队列函数
void LinkQueuePop(LinkQueue* q);
//取队首元素
int LinkQueueFront(LinkQueue* q,LinkQueueType* value);

linkqueue.c

#include"linkqueue.h"

void LinkQueueInit(LinkQueue* q){
    if(q == NULL){
        return;
    }
    q->head = NULL;
    q->tail = NULL;
    return;
}

LinkNode* LinkQueueCreateNode(LinkQueueType value){
    LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));
    if(new_node == 0){
        return NULL;
    }
    new_node->next = NULL;
    new_node->data = value;
    return new_node;
}

void DestroyNode(LinkNode* to_delete){
    if(to_delete == NULL){
        return;
    }
    free(to_delete);
    return;
}

void LinkQueuePush(LinkQueue* q,LinkQueueType value){
    if(q == NULL){
        return;
    }
    LinkNode* new_node = LinkQueueCreateNode(value);
    if(q->head == NULL){
        q->head = new_node;
        q->tail = new_node;
        return;
    }
    q->tail->next = new_node;
    q->tail = q->tail->next;
    return;
}

void LinkQueuePrint(LinkQueue* q,const char* msg){
    if(q == NULL){
        return;
    }
    printf("[ %s ]:\n",msg);
    LinkNode* cur = q->head;
    while(cur != NULL){
        printf("[%c][%p]<-",cur->data,cur);
        cur = cur->next;
    }
    printf("NULL\n\n");
    return;
}

void LinkQueuePop(LinkQueue* q){
    if(q == NULL){
        return;
    }
    if(q->head == NULL){
        return;
    }
    LinkNode* temp = q->head;
    q->head = q->head->next;
    DestroyNode(temp);
    return;
}

int LinkQueueFront(LinkQueue* q,LinkQueueType* value){
    if(q == NULL){
        return 0;
    }
    *value = q->head->data;
    return 1;
}

以上就是关于链式队列的介绍。
由于我的能力有限,上面的介绍可能有不妥或者Bug,欢迎发邮件到我的邮箱(Cyrus_wen@163.com)批评指正!

<think>首先,用户的问题是:“我想比较链式队列顺序队列的差异 请问链式队列顺序队列的区别”。我需要基于系统指令提供的引用来回答。 系统指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 - 参考提供的引用。 提供的引用是关于队列的: - 引用[1]:顺序队列(循环队列链式队列。 - 引用[2]:链式队列顺序队列的性能比较。 - 引用[3]:链式队列的基本特性。 - 引用[4]:Java实现链式队列顺序循环队列。 - 引用[5]:顺序队列链式队列的代码实现。 关键点: - 顺序队列(通常指循环队列)使用数组存储。 - 链式队列使用表存储。 - 区别包括存储结构、性能、适用场景等。 我需要结构化回答: 1. 介绍队列的基本概念。 2. 解释顺序队列(循环队列)。 3. 解释链式队列。 4. 比较两者的差异。 5. 生成相关问题。 差异点从引用中提取: - 存储结构:顺序队列用数组,链式队列表。 - 内存管理:顺序队列有固定大小,链式队列动态增长。 - 性能:引用[2]提到链式队列在频繁插入/删除时效率高,顺序队列在随机访问时效率高。 - 适用场景:引用[3]说链式队列适合数据元素变动大的情形。 - 实现细节:如循环队列如何避免浪费空间。 使用LaTeX:如果有数学表达式,比如索引计算,但队列比较中可能没有直接数学公式。我可以提到一些概念,如队列操作的时间复杂度: - 入操作:在链式队列中通常是$O(1)$,在顺序队列中也是$O(1)$(如果循环实现)。 - 但需要确保使用$...$格式。 例如:在顺序循环队列中,计算尾索引使用$(rear + 1) \% size$ [^5]。 生成相关问题:在回答结束时,添加相关问题。 引用标识:在回答中引用时,末尾添加引用标识。例如,根据引用[2],链式队列在频繁插入删除时效率更高[^2]。 回答结构: - 开头简要介绍。 - 然后分点比较差异。 - 最后生成相关问题。 大纲: 1. 引言:队列是先进先出(FIFO)的数据结构。 2. 顺序队列:使用数组存储,实现为循环队列以避免空间浪费。 - 特点:固定大小,高效随机访问。 3. 链式队列:使用表存储。 - 特点:动态大小,适合变动大的数据。 4. 比较差异: - 存储结构 - 内存管理 - 性能(插入、删除、访问) - 适用场景 5. 相关问题。 确保中文回答。</think>### 链式队列顺序队列的区别 队列是一种先进先出(FIFO)的数据结构,常用于任务调度、缓冲区管理等场景。链式队列顺序队列是两种主要实现方式,它们在存储结构、性能、适用场景等方面存在显著差异。下面我将基于数据结构原理实际应用,逐步比较它们的区别,确保回答真实可靠。 #### 1. **存储结构与实现方式** - **顺序队列(通常指顺序循环队列)**: 使用数组(连续内存空间)存储数据元素。为避免入操作导致的数据移动空间浪费,它通常实现为循环队列。例如,尾索引通过公式 $(rear + 1) \% size$ 计算,头索引通过 $(front + 1) \% size$ 更新,从而循环利用数组空间[^1][^5]。 特点:固定大小(需预先分配内存),不支持动态扩容。 示例代码(C语言): ```c typedef struct { int data[MAXSIZE]; // 固定大小数组 int front; // 头指针 int rear; // 尾指针 } SqQueue; ``` 在初始化时,需指定数组大小(如 `MAXSIZE`),出操作不移动元素,仅修改指针[^5]。 - **链式队列**: 使用表(节点动态分配)存储数据元素。每个节点包含数据指向下一个节点的指针。头指针指向头结点,尾指针指向尾结点,入在尾部添加节点,出在头部删除节点[^3][^4]。 特点:动态大小(无需预先分配),支持无限增长(受内存限制)。 示例代码(Java): ```java class Node { int data; Node next; } class LinkedQueue { Node front; // 头指针 Node rear; // 尾指针 } ``` 链式队列通常设计为带头结点的单表,使插入删除操作统一且高效[^3]。 #### 2. **内存管理与空间效率** - **顺序队列**: 内存静态分配,数组大小固定。可能导致空间浪费(如队列未满时)或溢出(队列满时无法入)。循环队列通过公式 $(rear + 1) \% size == front$ 判断队列满,空间利用率较高,但仍有最大容量限制[^1][^5]。 - **链式队列**: 内存动态分配,节点按需创建释放。无固定大小限制,适合数据元素变动较大的场景(如频繁添加或删除)。但每个节点需额外存储指针,空间开销稍大(约增加 $O(n)$ 额外空间)[^3][^4]。 #### 3. **性能比较(时间复杂度分析)** 关键操作的时间复杂度如下(假设 $n$ 为队列元素数): - **入操作(Enqueue)**: - 顺序队列:$O(1)$(循环队列直接计算索引,无数据移动)[^5]。 - 链式队列:$O(1)$(在尾部添加节点,指针操作)[^3][^4]。 两者均为常数时间,但顺序队列队列满时需拒绝入或扩容(需复制数据,导致 $O(n)$ 开销),而链式队列无此问题。 - **出操作(Dequeue)**: - 顺序队列:$O(1)$(修改头指针)[^5]。 - 链式队列:$O(1)$(删除头结点)[^3][^4]。 同样高效,但顺序队列后数组位置可能闲置,直到循环利用。 - **随机访问**: - 顺序队列:$O(1)$(数组支持直接索引访问,如访问第 $i$ 个元素)[^2]。 - 链式队列:$O(n)$(需遍历表)[^2][^4]。 顺序队列在需要快速访问元素时优势明显。 - **整体性能场景**: - 链式队列在频繁插入删除操作时效率更高,因为无固定大小约束复制开销[^2]。 - 顺序队列在随机访问元素或内存受限时效率更高,且缓存友好(数据连续存储)[^2][^5]。 #### 4. **适用场景** - **顺序队列**: 适合数据规模固定、需要高效随机访问的场景,如嵌入式系统(内存受限)、循环缓冲区(如网络包处理)[^1][^5]。 缺点:不适用于元素数量变化大的情况,可能导致溢出或空间浪费。 - **链式队列**: 适合数据元素变动频繁、无法预估队列大小的场景,如任务调度系统(任务动态添加)、消息队列(高并发入)[^3][^4]。 缺点:额外指针开销碎片化内存可能影响性能。 #### 总结 | 特性 | 顺序队列(循环队列) | 链式队列 | |--------------|--------------------------------------|------------------------------| | 存储结构 | 数组(连续内存) | 表(动态节点) | | 内存管理 | 固定大小,可能浪费或溢出 | 动态大小,无上限 | | 入/出 | $O(1)$(队列未满/未空时) | $O(1)$ | | 随机访问 | $O(1)$ | $O(n)$ | | 空间效率 | 较高(无指针开销) | 较低(有指针开销) | | 适用场景 | 固定大小数据、高效访问 | 变动大数据、频繁插入删除 | 通过以上比较,您可以根据具体需求选择:顺序队列更适合内存敏感随机访问场景,而链式队列更灵活,适合动态数据环境[^1][^2][^3][^4][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值