队列的优化

来源:互联网 发布:怎样配置java环境变量 编辑:程序博客网 时间:2024/05/17 03:02
顺序队列的瓶颈:

顺序队列:

 线性表的第一个元素作为队头;
 线性表的最后一个元素作为队尾;
 入队的新元素是在线性表的最后时间复杂度为O(1);

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

顺序队列的优化方案:
 定义front使其始终代表队头的下标;
 出队时将队头元素返回且front++;
 定义rear使其始终代表队尾下一个元素的下标;
 入队时将新元素插入 且rear++;

没有必要只将下标为0的位置定义为队头!!!



顺序队列的关键状态
 初始状态:length == 0, front == 0, rear == 0;
 空队列状态:length == 0, front == rear;
 满队列状态:length == capacity, front == rear;
 循环使用队列中的空间
 入队:rear = (rear + 1) % capacity;
 出队:front = (front + 1) % capacit
y;


#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 )//合法性判断,至少保证队列容量大于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;//rear应到下一个位置,因为要循环使用数组中的元素,因此需要取余  
        sQueue->length++;
    }   
    return ret;
}
void* SeqQueue_Retrieve(SeqQueue* queue) // O(1)
{
    TSeqQueue* sQueue = (TSeqQueue*)queue;
    void* ret = SeqQueue_Header(queue);//调用header,获取队头元素 
    if( ret != NULL )
    {
        sQueue->front = (sQueue->front + 1) % sQueue->capacity;//同rear      
        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;
}

链式队列的瓶颈:
 链式队列:
 线性表的第一个元素作为队头;
 线性表的最后一个元素作为队尾;
 入队的新元素是在线性表的最后 时间复杂度为O(n);
 出队的元素即链表的第一个元素时间复杂度为O(1);

链式队列的优化方案:
 定义rear指针始终指向链表中的最有一个元素;
 入队时将新元素通过rear插入队尾且将rear指向新元素;


链式队列的关键状态
 空队列状态:front == NULL, rear == NULL;
 关键操作
 入队:
• rear->next = node; 
• rear = node; 
• node->next = NULL;
 出队:
• front = front->next


#include <malloc.h>
#include <stdio.h>
#include "LinkQueue.h"
typedef struct _tag_LinkQueueNode TLinkQueueNode;//链式队列中的每一个结点
struct _tag_LinkQueueNode
{
    TLinkQueueNode* next;
    void* item;
};
typedef struct _tag_LinkQueue//链式队列的表头结点
{
    TLinkQueueNode* front;
    TLinkQueueNode* rear;
    int length;
} TLinkQueue;
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;
}
void LinkQueue_Destroy(LinkQueue* queue) // O(n)
{
    LinkQueue_Clear(queue);//因为申请了空间,必须清空
    free(queue);
}
void LinkQueue_Clear(LinkQueue* queue) // O(n)
{
    while( LinkQueue_Length(queue) > 0 )
    {
        LinkQueue_Retrieve(queue);//释放队列里的每一个结点
    }
}
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;//最后一个元素的next指针指向node
            sQueue->rear = node;//队尾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;//node指向第一个元素
        
        sQueue->front = node->next;//front移动到下一个元素
        
        ret = node->item;//node里面的给返回值
        
        free(node);//释放内存
        
        sQueue->length--;
        
        if( sQueue->length == 0 )//如果元素删完,则恢复至初始状态
        {
            sQueue->front = NULL;
            sQueue->rear = NULL;
        }
    }
    return ret;
}
void* LinkQueue_Header(LinkQueue* queue) // O(1)
{
    TLinkQueue* sQueue = (TLinkQueue*)queue;
    void* ret = NULL;    
    if( (sQueue != NULL) && (sQueue->length > 0) )
    {
        ret = sQueue->front->item;
    }
    
    return ret;
}
int LinkQueue_Length(LinkQueue* queue) // O(1)
{
    TLinkQueue* sQueue = (TLinkQueue*)queue;
    int ret = -1;
    
    if( sQueue != NULL )
    {
        ret = sQueue->length;
    }
    
    return ret;
}

优化的顺序队列循环利用顺序空间提高出队操作的效率;
优化的链式队列定义rear rear指针指向队尾元素 指针指向队尾元素提高出队操作的效率;

0 0