您的位置:首页 > 理论基础 > 数据结构算法

数据结构学习笔记(8.循环队列与链队列)

2014-03-31 23:20 771 查看

本节知识点:

1.队列的概念:

    a.队列也是一种特殊的线性表,队列仅在线性表的两端进行操作,队头:取出数据元素的一端、队尾:插入数据元素的一端!    b.队列的性质:先进先出(FIFO)


     对于普通的链式队列和顺序队列来说,具体的实现方式跟链式栈和顺序栈一样,只不过无所谓哪边是队列头、哪边是队列尾。因为时间复杂度必然有一端为O(1),另一端为O(N)!对于这样的复杂度,我们就应该想办法使它都降到O(1),所以就引入了循环队列!

2.循环队列:





代码如下:
SeqQueue.c文件:
/************************************************************************************
文件名:SeqQueue.c
头文件:SeqQueue.h
时间: 2014/03/31
作者: Hao
功能:可以复用的顺序循环队列 即入队列和出队列的时间复杂度都为O(1)
************************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include "SeqQueue.h"

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

/************************************************************************************
函数名: SeqQueue_Create
函数功能: 创建一个容量为capacity的循环队列
参数: int capacity 创建循环队列中成员的个数 即循环队列容量
返回值: void* ret 如果返回NULL 说明创建循环队列失败
如果返回ret 说明创建循环队列成功 且ret为描述循环队列的结构体
************************************************************************************/
SeqQueue* SeqQueue_Create(int capacity)
{
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);
}
}
else
{
ret = NULL;
}
return (SeqQueue*)ret;
}

/************************************************************************************
函数名: SeqQueue_Destroy
函数功能: 销毁循环队列 free开辟的内存
参数: void* list 描述循环队列结构体指针
返回值: void
************************************************************************************/
void SeqQueue_Destroy(SeqQueue* queue)
{
free(queue);
}

/************************************************************************************
函数名: SeqQueue_Clear
函数功能:清空循环队列 其实就是给length=0; front = 0 rear = 0;
函数参数:SeqQueue* queue 描述循环队列结构体指针
函数返回值:int ret 成功返回0
失败返回-1
************************************************************************************/
int SeqQueue_Clear(SeqQueue* queue)
{
int ret;
TSeqQueue *Tqueue = (TSeqQueue* )queue;
/*函数参数合法性检测*/
if(NULL != Tqueue)
{
Tqueue->length = 0;
Tqueue->front = 0;
Tqueue->rear = 0;
ret=0;
}
else
ret=-1;
return ret;
}

/************************************************************************************
函数名: SeqQueue_Length
函数功能:获得循环队列 现在的大小
函数参数:void* list 描述循环队列结构体指针
函数返回值:int ret 成功返回length
失败返回-1
************************************************************************************/
int SeqQueue_Length(SeqQueue* queue)
{
int ret;
TSeqQueue *Tqueue = (SeqQueue* )queue;
/*函数参数合法性检测*/
if(NULL != Tqueue)
{
ret = Tqueue->length;
}
else
ret = -1;
return ret;
}

/************************************************************************************
函数名: SeqQueue_Capacity
函数功能:获得循环队列 的容量
函数参数:void* list 描述循环队列结构体指针
函数返回值:int ret 成功返回capacity
失败返回-1
************************************************************************************/
int SeqQueue_Capacity(SeqQueue* queue)
{
int ret;
TSeqQueue *Tqueue = (SeqQueue* )queue;
/*函数参数合法性检测*/
if(NULL != Tqueue)
{
ret = Tqueue->capacity;
}
else
ret = -1;
return ret;
}

/************************************************************************************
函数名: SeqQueue_Push
函数功能:入队操作
函数参数:SeqQueue* queue入队队列, void* data入队数据元素
这个队列是从尾部入队rear 从头部出队front
函数返回值:int ret 成功返回 1
失败返回 0
************************************************************************************/
int SeqQueue_Push(SeqQueue* queue, void* data)
{
TSeqQueue* Tqueue = (TSeqQueue*)queue;
int ret = (Tqueue != NULL) && (data != NULL); //安全性检测
ret = ret && (Tqueue->length + 1 <= Tqueue->capacity); //容量检测
if(ret)
{
Tqueue->node[Tqueue->rear] = data;
Tqueue->rear = (Tqueue->rear + 1) % Tqueue->capacity;
Tqueue->length++;
}

return ret;
}

/************************************************************************************
函数名: SeqQueue_Pop
函数功能:出队操作
函数参数:SeqQueue* queue出队队列
这个队列是从尾部入队rear 从头部出队front
函数返回值:void* ret 成功返回 数据元素地址
失败返回 NULL
************************************************************************************/
void* SeqQueue_Pop(SeqQueue* queue)
{
TSeqQueue* Tqueue = (TSeqQueue*)queue;
void* ret = NULL;
if((Tqueue != NULL) && (Tqueue->length > 0))
{
ret = (void*)(Tqueue->node[Tqueue->front]);
Tqueue->front = (Tqueue->front + 1) % Tqueue->capacity;
Tqueue->length--;
}
return ret;
}

/************************************************************************************
函数名: SeqQueue_Top
函数功能:获得队尾元素地址
函数参数:SeqQueue* queue出队队列
这个队列是从尾部入队rear 从头部出队front
函数返回值:void* ret 成功返回 队尾数据元素地址
失败返回 NULL
************************************************************************************/
void* SeqQueue_Top(SeqQueue* queue)
{
TSeqQueue* Tqueue = (TSeqQueue*)queue;
void* ret = NULL;
if((Tqueue != NULL) && (Tqueue->length > 0))
{
ret = (void*)(Tqueue->node[Tqueue->front]);
}
return ret;
}


SeqQueue.h文件:
#ifndef _SeqQueue_H_
#define _SeqQueue_H_

typedef void SeqQueue;

SeqQueue* SeqQueue_Create(int capacity);

void SeqQueue_Destroy(SeqQueue* queue);

int SeqQueue_Clear(SeqQueue* queue);

int SeqQueue_Push(SeqQueue* queue, void* data);

void* SeqQueue_Pop(SeqQueue* queue);

void* SeqQueue_Top(SeqQueue* queue);

int SeqQueue_Length(SeqQueue* queue);

int SeqQueue_Capacity(SeqQueue* queue);

#endif

main.c文件:
#include <stdio.h>
#include <stdlib.h>
#include "SeqQueue.h"

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_Push(queue, a + i);
}

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

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

printf("\n");

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

SeqQueue_Push(queue, a + i);
printf("Pop: %d\n", *(int*)SeqQueue_Pop(queue));
}

SeqQueue_Destroy(queue);

return 0;
}
注意:其实循环队列就是在一段内存空间中,使用front和rear变量夹住一端空间,使其成为顺序队列,并且入队列和出队列的时间复杂度都是O(1)

3.链式队列:





示例代码:
LinkQueue.c文件:
/*******************************************************************************************************
文件名:LinkQueue.c
头文件:LinkQueue.h
时间: 2013/03/31
作者: Hao
功能: 可以复用 链式队列
*******************************************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include "LinkQueue.h"

typedef struct str_linkqueue
{
LinkQueueNode* front;
LinkQueueNode* rear;
int length;
}link_queue;

/*******************************************************************************************************
函数名: Creat_LinkQueueHead
函数功能:创建一个链式队列头 并给队列头分配空间
参数: void
返回值:ret 成功返回链表头地址 失败返回NULL
*******************************************************************************************************/
LinkQueue* Creat_LinkQueueHead(void)
{
link_queue* ret = NULL;
ret = (link_queue* )malloc( sizeof(link_queue)*1 );
if(NULL != ret) //malloc分配成功
{
ret -> length = 0;
ret -> front = NULL;
ret -> rear = NULL;
}
return (LinkQueue* )ret;
}

/*******************************************************************************************************
函数名: Get_Length
函数功能:获得链式队列的长度
参数: LinkQueue* queue 描述队列的结构体
返回值:ret 成功返回队列长度 失败返回0
*******************************************************************************************************/
int Get_Length(LinkQueue* queue)
{
int ret = 0;
link_queue* lqueue = (link_queue* )queue;
if( NULL != lqueue )
{
ret = lqueue -> length;
}
return ret;
}

/*******************************************************************************************************
函数名: LinkQueue_Push
函数功能:把数据data从队尾加入队列中
参数: LinkQueue* queue 描述队列的结构体 void* data 要加入队列数据的地址
返回值:ret 成功返回1 失败返回0
*******************************************************************************************************/
int LinkQueue_Push(LinkQueue* queue, void* data)
{
link_queue* lqueue = (link_queue* )queue;
int ret = ((NULL != lqueue)&&(NULL != data));
if(ret)
{
LinkQueueNode* node = (LinkQueueNode*)malloc(sizeof(LinkQueueNode));
if(NULL != node)
{
node -> Queuedata = data;
if(lqueue -> length == 0)
{
lqueue -> front = node;
lqueue -> rear = node;
node -> next = NULL;
}
else
{
lqueue -> rear -> next = node;
lqueue -> rear = node;
node -> next = NULL;
}
lqueue -> length++;
}

}

return ret;
}

/*******************************************************************************************************
函数名: LinkQueue_Pop
函数功能:把数据从队头取出
参数: LinkQueue* queue 描述队列的结构体
返回值:ret 成功返回取出数据地址 失败返回NULL
*******************************************************************************************************/
void* LinkQueue_Pop(LinkQueue* queue)
{
void* ret = NULL;
LinkQueueNode* node = NULL;
link_queue* lqueue = (link_queue* )queue;

if((NULL != lqueue)&&(lqueue->length > 0))
{
node = lqueue->front;
lqueue->front = lqueue->front->next;
lqueue->length--;
ret = node->Queuedata;
free(node);

if(lqueue->length == 0)
{
lqueue->front = NULL; //其实理论上可以不给front赋值NULL的
lqueue->rear = NULL;
}
}
return ret;
}

/*******************************************************************************************************
函数名: LinkQueue_Top
函数功能:获得队头数据地址
参数: LinkQueue* queue 描述队列的结构体
返回值:ret 成功返回取出数据地址 失败返回NULL
*******************************************************************************************************/
void* LinkQueue_Top(LinkQueue* queue)
{
void* ret = NULL;

link_queue* lqueue = (link_queue* )queue;

if((NULL != lqueue)&&(lqueue->length > 0))
{
ret = lqueue->front->Queuedata;

}
return ret;
}

/*******************************************************************************************************
函数名: Clean_LinkQueue
函数功能:清空队列
参数: LinkQueue* queue 描述队列的结构体
返回值:ret 成功返回1 失败返回0
*******************************************************************************************************/
int Clean_LinkQueue(LinkQueue* queue)
{
int ret = 0;
void* temp = NULL;
if(NULL != queue)
{
ret = 1;
while(Get_Length(queue))
{
temp = LinkQueue_Pop(queue);
if(NULL == temp)
{
ret = 0;
break;
}
}

}
return ret;
}

/*******************************************************************************************************
函数名: Destroy_LinkQueue
函数功能:清空队列并且销毁队列头
参数: LinkQueue* queue 描述队列的结构体
返回值:ret 成功返回1 失败返回0
*******************************************************************************************************/
void Destroy_LinkQueue(LinkQueue* queue)
{
Clean_LinkQueue(queue);
free(queue);
}


LinkQueue.h 文件:#ifndef __LinkQueue_H__
#define __LinkQueue_H__

typedef void LinkQueue; //这个是为了 封装方便
typedef struct Str_LinkQueue LinkQueueNode; //这个结构体是链表的真身
struct Str_LinkQueue
{
LinkQueueNode* next;
void* Queuedata;
};

LinkQueue* Creat_LinkQueueHead(void);

void Destroy_LinkQueue(LinkQueue* queue);

int Get_Length(LinkQueue* queue);

int Clean_LinkQueue(LinkQueue* queue);

int LinkQueue_Push(LinkQueue* queue, void* data);

void* LinkQueue_Pop(LinkQueue* queue);

void* LinkQueue_Top(LinkQueue* queue);

#endif

main.c 文件:#include <stdio.h>
#include "LinkQueue.h"

int main()
{
LinkQueue* queue = Creat_LinkQueueHead();
int a[10] = {0};
int i = 0;

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

LinkQueue_Push(queue, a + i);
}

printf("Pop: %d\n", *(int*)LinkQueue_Pop(queue));
printf("Top: %d\n", *(int*)LinkQueue_Top(queue));
printf("Length: %d\n", Get_Length(queue));

//Clean_LinkQueue(queue);

while( Get_Length(queue) > 0 )
{
printf("Pop: %d\n", *(int*)LinkQueue_Pop(queue));
}

Destroy_LinkQueue(queue);
return 0;
}
注意:链队列,无非就是定义了两个指针,分别指向队列头和队列尾,这样找到队头和队尾的时间复杂度就是O(1)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: