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

本节知识点:

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)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值