第18课——队列的优化实现

之前实现的顺序栈和链式栈的进栈和出栈操作时间复杂度都是O(1)。而用同样的方式实现队列,进队和出队的复杂度总有一个是O(n) 。
顺序队列的瓶颈

顺序队列

线性表的第一个元素作为队头

线性表的最后一个元素作为队尾

入队的新元素是在线性表的最后,时间复杂度为O(1);

出队时需要将后续的所有元素向前移动,时间复杂度为O(n);

顺序队列的优化方案

定义顺序队列的头:

typedef unsigned int TSeqQueueNode;

typedef struct _tag_SeqQueue
{
    int capacity;
    int length;
    int front;
    int rear;
    TSeqQueueNode* node;
} TSeqQueue;

顺序队列的创建

SeqQueue* SeqQueue_Create(int capacity) // O(1)
{
    TSeqQueue* ret = NULL;

    if( capacity >= 0 )
    {
        ret = (TSeqQueue*)malloc(sizeof(TSeqQueue) + sizeof(TSeqQueueNode) * capacity);
    }

    if( ret != NULL )
    {
        ret->capacity = capacity;
        ret->length = 0;
        ret->front = 0;
        ret->rear = 0;
        ret->node = (TSeqQueueNode*)(ret + 1);
    }
    return ret;
}

入队列

int SeqQueue_Append(SeqQueue* queue, void* item) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    int ret = (sQueue != NULL) && (item != NULL);

    ret = ret && (sQueue->length + 1 <= sQueue->capacity);

    if( ret )
    {
        sQueue->node[sQueue->rear] = (TSeqQueueNode)item;

        sQueue->rear = (sQueue->rear + 1) % sQueue->capacity;

        sQueue->length++;
    }
    return ret;
}

出队列

void* SeqQueue_Retrieve(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    void* ret = SeqQueue_Header(queue);

    if( ret != NULL )
    {
        sQueue->front = (sQueue->front + 1) % sQueue->capacity;

        sQueue->length--;
    }

    return ret;
}

void* SeqQueue_Header(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    void* ret = NULL;

    if( (sQueue != NULL) && (sQueue->length > 0) )
    {
        ret = (void*)(sQueue->node[sQueue->front]);
    }

    return ret;
}

出队列由原来的O(n)变成的O(1);

完整版seqQueue.c代码:

#include <stdio.h>
#include <malloc.h>
#include "SeqQueue.h"

typedef unsigned int TSeqQueueNode;

typedef struct _tag_SeqQueue
{
    int capacity;
    int length;
    int front;
    int rear;
    TSeqQueueNode* node;
} TSeqQueue;

SeqQueue* SeqQueue_Create(int capacity) // O(1)
{
    TSeqQueue* ret = NULL;

    if( capacity >= 0 )
    {
        ret = (TSeqQueue*)malloc(sizeof(TSeqQueue) + sizeof(TSeqQueueNode) * capacity);
    }

    if( ret != NULL )
    {
        ret->capacity = capacity;
        ret->length = 0;
        ret->front = 0;
        ret->rear = 0;
        ret->node = (TSeqQueueNode*)(ret + 1);
    }

    return ret;
}

void SeqQueue_Destroy(SeqQueue* queue) // O(1)
{
    free(queue);
}

void SeqQueue_Clear(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;

    if( sQueue != NULL )
    {
        sQueue->length = 0;
        sQueue->front = 0;
        sQueue->rear = 0;
    }
}

int SeqQueue_Append(SeqQueue* queue, void* item) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    int ret = (sQueue != NULL) && (item != NULL);

    ret = ret && (sQueue->length + 1 <= sQueue->capacity);

    if( ret )
    {
        sQueue->node[sQueue->rear] = (TSeqQueueNode)item;

        sQueue->rear = (sQueue->rear + 1) % sQueue->capacity;

        sQueue->length++;
    }

    return ret;
}

void* SeqQueue_Retrieve(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    void* ret = SeqQueue_Header(queue);

    if( ret != NULL )
    {
        sQueue->front = (sQueue->front + 1) % sQueue->capacity;

        sQueue->length--;
    }

    return ret;
}

void* SeqQueue_Header(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    void* ret = NULL;

    if( (sQueue != NULL) && (sQueue->length > 0) )
    {
        ret = (void*)(sQueue->node[sQueue->front]);
    }

    return ret;
}

int SeqQueue_Length(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    int ret = -1;

    if( sQueue != NULL )
    {
        ret = sQueue->length;
    }

    return ret;
}

int SeqQueue_Capacity(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    int ret = -1;

    if( sQueue != NULL )
    {
        ret = sQueue->capacity;
    }

    return ret;
}

SeqQueue.c

main.c

#include <stdio.h>
#include <stdlib.h>
#include "SeqQueue.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[])
{
    SeqQueue* queue = SeqQueue_Create(6);
    int a[10] = {0};
    int i = 0;

    for(i=0; i<10; i++)
    {
        a[i] = i + 1;

        SeqQueue_Append(queue, a + i);
    }

    printf("Header: %d\n", *(int*)SeqQueue_Header(queue));
    printf("Length: %d\n", SeqQueue_Length(queue));
    printf("Capacity: %d\n", SeqQueue_Capacity(queue));

    while( SeqQueue_Length(queue) > 0 )
    {
        printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));
    }

    printf("\n");

    for(i=0; i<10; i++)
    {
        a[i] = i + 1;

        SeqQueue_Append(queue, a + i);

        printf("Retrieve: %d\n", *(int*)SeqQueue_Retrieve(queue));
    }

    SeqQueue_Destroy(queue);

    return 0;
}

运行结果为:

同样的,我们来实现链式队列;

链式队列的头:

typedef struct _tag_LinkQueue
{
    TLinkQueueNode* front;
    TLinkQueueNode* rear;
    int length;
} TLinkQueue;

节点:

struct _tag_LinkQueueNode
{
    TLinkQueueNode* next;
    void* item;
};

创建:

LinkQueue* LinkQueue_Create() // O(1)
{
    TLinkQueue* ret = (TLinkQueue*)malloc(sizeof(TLinkQueue));

    if( ret != NULL )
    {
        ret->front = NULL;
        ret->rear = NULL;
        ret->length = 0;
    }

    return ret;
}

入队列:

int LinkQueue_Append(LinkQueue* queue, void* item) // O(1)
{
    TLinkQueue* sQueue = (TLinkQueue*)queue;
    TLinkQueueNode* node = (TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));
    int ret = (sQueue != NULL ) && (item != NULL) && (node != NULL);

    if( ret )
    {
        node->item = item;

        if( sQueue->length > 0 )
        {
            sQueue->rear->next = node;
            sQueue->rear = node;
            node->next = NULL;
        }
        else
        {
            sQueue->front = node;
            sQueue->rear = node;
            node->next = NULL;
        }
        sQueue->length++;
    }

    if( !ret )
    {
        free(node);
    }
    return ret;
}

出队列:

void* LinkQueue_Retrieve(LinkQueue* queue) // O(1)
{
    TLinkQueue* sQueue = (TLinkQueue*)queue;
    TLinkQueueNode* node = NULL;
    void* ret = NULL;

    if( (sQueue != NULL) && (sQueue->length > 0) )
    {
        node = sQueue->front;

        sQueue->front = node->next;

        ret = node->item;

        free(node);

        sQueue->length--;

        if( sQueue->length == 0 )
        {
            sQueue->front = NULL;
            sQueue->rear = NULL;
        }
    }

    return ret;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "LinkQueue.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[])
{
    LinkQueue* queue = LinkQueue_Create();
    int a[10] = {0};
    int i = 0;

    for(i=0; i<10; i++)
    {
        a[i] = i + 1;

        LinkQueue_Append(queue, a + i);
    }

    printf("Header: %d\n", *(int*)LinkQueue_Header(queue));
    printf("Length: %d\n", LinkQueue_Length(queue));

   // LinkQueue_Clear(queue);

    while( LinkQueue_Length(queue) > 0 )
    {
        printf("Retrieve: %d\n", *(int*)LinkQueue_Retrieve(queue));
    }

    LinkQueue_Destroy(queue);

    return 0;
}

运行结果:

优化后的队列,增加了front,rear后,入队和出队都是O(1);

原文地址:https://www.cnblogs.com/Liu-Jing/p/9574572.html

时间: 2024-11-01 17:39:45

第18课——队列的优化实现的相关文章

数据--第23课 - 队列的优化实现

第23课 - 队列的优化实现 1. 顺序队列的瓶颈 顺序队列 线性表的第一个元素作为队头. 线性表的最后一个元素作为队尾. 入队的新元素是线性表的最后,时间复杂度为O(1). 出队列时需要将后续的所有元素向前移动,时间复杂度是O(n). 2. 顺序队列的优化方案 (1)定义front使其始终代表队头的下标. 出队列时对头元素返回,且front++ (2)定义rear使其始终代表队尾下一个元素的下标. 出队时将新的元素插入,且rear++ (3)没有必要只将下标为0的位置定义为队头. (4)顺序队

七月算法--12月机器学习在线班-第四次课笔记—凸优化

七月算法--12月机器学习在线班-第四次课笔记—凸优化 七月算法(julyedu.com)12月机器学习在线班学习笔记 http://www.julyedu.com

HDU 3507 单调队列 斜率优化

斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方法来做,但是该题要求的是区间和的平方,于是要转换单调的计算方法为斜率,也就是凸线. 其他就是最基本的单调DP /** @Date : 2017-09-04 15:39:05 * @FileName: HDU 3507 单调队列 斜率优化 DP.cpp * @Platform: Windows * @

多线程下队列的优化

0. 前言 前段时间在看无锁队列相关的东西时发现了一篇关于加锁队列算法优化的文章,故看了下其原理以及使用C实现了该队列.该队列在Java中类LinkedBlockingQueue以及实现了该功能. 相关文章:Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 多线程队列的算法优化 1. 基本原理 对于多线程下,多生产者以及多消费者的环境下,可以通过在队首以及队尾分开加锁进行优化.初始时

Spark IMF传奇行动第18课:RDD持久化、广播、累加器总结

昨晚听了王家林老师的Spark IMF传奇行动第18课:RDD持久化.广播.累加器,作业是unpersist试验,阅读累加器源码看内部工作机制: scala> val rdd = sc.parallelize(1 to 1000) rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:21 scala> rdd.persist res0: rdd.type

3月3日完成第17课,准备开始第18课

昨天,也就是3月3日终于完成word文档"lvs+keepalived集群架构服务应用指南.doc"第17课的部分.之前,又完成1节51cto学院里,oldboy关于职业发展的视频笔记"linux运维人员需要具备的技能说明". 本来的计划是春节前完成第17课,没想到又拖成2个月. 第18课估计也不会好到那里去-- 我现在又开始纠结到底要不要进行MySQL的最后1课了,在公司根本就用不到MySQL.是不是要在换工作之前,先把4节shell课程完成再说呢? 先学能用的,

第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据

第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据 ADO.NET 为什么要学习? 我们要搭建一个平台(Web/Winform)让用户方便的操作数据库中的数据. 什么是ADO.NET 是一组库类,System.Data. Ado.net组成 Connection:用来连接数据库 Command:用来执行SQL语句 DataReader:只读.只进的结果集,一条一条读取数据(SteamReader.XmlReader) Da

微信后台异步消息队列的优化升级实践分享

1.引言 MQ 异步消息队列是微信后台自研的重要组件,广泛应用在各种业务场景中,为业务提供解耦.缓冲.异步化等能力.本文分享了该组件2.0版本的功能特点及优化实践,希望能为类似业务(比如移动端IM系统等)的消息队列设计提供一定的参考. 2.关于分享者 廖文鑫,2013年加入腾讯,从事微信后台基础功能及架构的开发和运营,先后参与了消息通知推送系统.任务队列组件.春晚摇红包活动等项目,在海量分布式高性能系统方面有丰富的经验. 3.背景介绍 微信后台给件 MQ 1.0 发布之初,基本满足了一般业务场景

Linux运维第七课----Linux基础优化

一.find找出文件,并替换文件内容[[email protected] ~/data]# find /root/data/ -type f -name '.txt' ./oldboy.txt./acheng.txt./magua.txt./op.txt1.方法一 [[email protected] ~/data]# find /root/data/ -type f -name '.txt' -exec sed -i 's#sh#hs#g'[[email protected] ~/data]#