5.队列

Posted 夜行过客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5.队列相关的知识,希望对你有一定的参考价值。

一.Queue 基本概念

队列是一种特殊的线性表

队列仅在线性表的两端进行操作

队头(Front):取出数据元素的一端

队尾(Rear):插入数据元素的一端

队列不允许在中间部位进行操作!

常用操作

  • 销毁队列
  • 清空队列
  • 进队列
  • 出队列
  • 获取队头元素
  • 获取队列的长度

二.队列的顺序存储设计与实现

seqlist.h

#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__

#define DLL_API  __declspec(dllexport)    //_declspec(dllexport):导出标志

typedef void SeqList;
typedef void SeqListNode;


// 创建线性表
DLL_API SeqList* SeqList_Create(int capacity);

// 销毁线性表
DLL_API void SeqList_Destroy(SeqList *list);

// 清空线性表
DLL_API void SeqList_Clear(SeqList *list);

// 获得线性表的长度
DLL_API int SeqList_Length(SeqList *list);

// 获得线性表的容量
DLL_API int SeqList_Capacity(SeqList *list);

// 向线性表中插入一个元素
DLL_API int SeqList_Insert(SeqList *list, SeqListNode *node, int pos);

// 获取线性表中某一个位置的元素
DLL_API SeqListNode* SeqList_Get(SeqList *list, int pos);

// 删除线性表中某一个位置的元素
DLL_API SeqListNode* SeqList_Delete(SeqList *list, int pos);



#endif

seqlist.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqlist.h"


typedef struct _tag_SeqList
{
    int capacity;
    int length;
    unsigned int *node; // unsigned int array[capacity]
}TSeqList;



// 创建线性表
SeqList* SeqList_Create(int capacity)
{
    TSeqList *ret = NULL;
    if (capacity < 0)
    {
        return NULL;
    }
    ret = malloc(sizeof(TSeqList) + sizeof(unsigned int)*capacity);
    if (ret == NULL)
    {
        return NULL;
    }
    memset(ret, 0, sizeof(TSeqList)+sizeof(unsigned int)*capacity);
    ret->node = (unsigned int *)(ret + 1); // ret 向后跳转sizeof(TSeqList)
    ret->capacity = capacity;
    ret->length = 0;

    return ret;
}


// 销毁线性表
void SeqList_Destroy(SeqList *list)
{
    if (list != NULL)
    {
        free(list);
    }

}


// 清空线性表
void SeqList_Clear(SeqList *list)
{
    TSeqList *tList = NULL;
    if (list == NULL)
    {
        return;
    }
    tList = (SeqList*)list;
    tList->length = 0;
}


// 获得线性表的长度
int SeqList_Length(SeqList *list)
{
    TSeqList *tList = NULL;
    tList = (TSeqList*)list;
    if (tList == NULL)
    {
        return -1;
    }
    return tList->length;
}



// 获得线性表的容量
int SeqList_Capacity(SeqList *list)
{
    TSeqList *tList = NULL;
    tList = (TSeqList*)list;
    if (tList == NULL)
    {
        return -1;
    }
    return tList->capacity;
}

// 向线性表中插入一个元素
DLL_API int SeqList_Insert(SeqList *list, SeqListNode *node, int pos)
{
    int i = 0;
    TSeqList *tList = NULL;
    tList = (TSeqList*)list;

    // 保证传入的线性表和元素节点不能为NULL
    if (list == NULL || node == NULL)
    {
        return -1;
    }

    // 判断该线性表是否已满
    if (tList->length >= tList->capacity)
    {
        return -2;
    }

    // 判断插入索引是否合法
    if (pos < 0 || pos >= tList->capacity)
    {
        return -3;
    }

    // 若索引值大于线性表当前长度,则将元素插入到线性表的末尾
    if (pos >= tList->length)
    {
        pos = tList->length;
    }

    // 插入算法
    // 将pos位置后的元素移次向后移
    for (i = tList->length; i > pos; i--)
    {
        // 更新后移元素的值
        tList->node[i] = tList->node[i - 1];
    }

    // 元素后移完毕后,将元素放到指定的位置
    tList->node[pos] = (unsigned int)node;
    tList->length ++;
    return 0;
}



// 获取线性表中某一个位置的元素
SeqListNode* SeqList_Get(SeqList *list, int pos)
{
    SeqListNode *ret = NULL;
    TSeqList *tList = NULL;
    tList = (TSeqList*)list;
    
    // 过滤非法参数
    if (list == NULL || pos < 0 || pos >= tList->length)
    {
        return NULL;
    }

    ret = (SeqListNode*)tList->node[pos];
    return ret;
}


// 删除线性表中某一个位置的元素
SeqListNode* SeqList_Delete(SeqList *list, int pos)
{
    int i = 0;
    TSeqList *tList = NULL;
    SeqListNode *ret = NULL;
    tList = (TSeqList*)list;

    if (list == NULL || pos < 0 || pos >= tList->length)
    {
        return NULL;
    }

    ret = (SeqListNode*)tList->node[pos];
    // 删除算法
    for (i=pos+1; i<tList->length; i++)
    {
        tList->node[i - 1] = tList->node[i];
    }
    tList->length--;

    return ret;
}

seqqueue.h

#ifndef __MY_SEQ_QUEUE_H__
#define __MY_SEQ_QUEUE_H__



typedef void SeqQueue;

// 创建队列
SeqQueue* SeqQueue_Create(int capacity);

// 销毁队列
void SeqQueue_Destroy(SeqQueue* queue);

// 清空队列
void SeqQueue_Clear(SeqQueue* queue);

// 向队尾添加元素
int SeqQueue_Append(SeqQueue* queue, void* item);

// 移除队列头部元素
void* SeqQueue_Retrieve(SeqQueue* queue);

// 获取队列头部元素
void* SeqQueue_Header(SeqQueue* header);

// 获取队列长度
int SeqQueue_Length(SeqQueue* length);

// 获取队列容量
int SeqQueue_Capacity(SeqQueue* queue);



#endif

seqqueue.c

#include "seqqueue.h"
#include "seqlist.h"


// 创建队列
SeqQueue* SeqQueue_Create(int capacity)
{
    return SeqList_Create(capacity);
}

// 销毁队列
void SeqQueue_Destroy(SeqQueue* queue)
{
    SeqList_Destroy(queue);
}

// 清空队列
void SeqQueue_Clear(SeqQueue* queue)
{
    SeqList_Clear(queue);
}

// 向队尾添加元素,相当于向线性表的尾部插入元素
int SeqQueue_Append(SeqQueue* queue, void* item)
{
    return SeqList_Insert(queue, item, SeqList_Length(queue));
}


// 移除队列头部元素
void* SeqQueue_Retrieve(SeqQueue* queue)
{
    return SeqList_Delete(queue, 0);
}


// 获取队列头部元素
void* SeqQueue_Header(SeqQueue* queue)
{
    return SeqList_Get(queue, 0);
}

// 获取队列长度
int SeqQueue_Length(SeqQueue* queue)
{
    return SeqList_Length(queue);
}

// 获取队列容量
int SeqQueue_Capacity(SeqQueue* queue)
{
    return SeqList_Capacity(queue);
}

运行结果:

current queue capacity is: 10

current queue length is: 6

current student age is: 12
current new length is: 0
请按任意键继续. . .

三.队列的链式存储设计与实现

linklist.h

#ifndef __MY_LINKLIST_H__
#define __MY_LINKLIST_H__

#define DLL_API  __declspec(dllexport)    //_declspec(dllexport):导出标志

typedef void LinkList;

typedef struct _tag_LinkListNode
{
    struct _tag_LinkListNode* next;      // 当前节点需要指向下一个节点的地址
}LinkListNode;




DLL_API LinkList* LinkList_Create();

DLL_API void LinkList_Destroy(LinkList *list);

DLL_API void LinkList_Clear(LinkList *list);

DLL_API int LinkList_Length(LinkList *list);

DLL_API int LinkList_Insert(LinkList *list, LinkListNode *node, int pos);

DLL_API LinkListNode* LinkList_Get(LinkList *list, int pos);

DLL_API LinkListNode* ListList_Delete(LinkList *list, int pos);


#endif

linklist.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"


typedef struct _tag_LinkList
{
    LinkListNode header;              //  链表中需要包含一个头节点
    int length;
}TLinkList;


// 创建链表
LinkList* LinkList_Create()
{
    TLinkList *ret = (TLinkList*)malloc(sizeof(TLinkList));
    if (ret == NULL) return NULL;
    memset(ret, 0, sizeof(TLinkList));

    ret->header.next = NULL;
    ret->length = 0;
    return ret;
}


// 销毁链表
void LinkList_Destroy(LinkList *list)
{
    if (list != NULL)
    {
        free(list);
    }
}


// 清空链表
void LinkList_Clear(LinkList *list)
{
    TLinkList *tList = NULL;
    if (list == NULL) return;
    
    tList = (TLinkList*)list;
    tList->header.next = NULL;
    tList->length = 0;
}


// 获取当前链表长度
int LinkList_Length(LinkList *list)
{
    TLinkList *tList = NULL;
    if (list == NULL) return -1;
    tList = (TLinkList*)list;

    return tList->length;
}


// 向当前链表插入数据
int LinkList_Insert(LinkList *list, LinkListNode *node, int pos)
{
    TLinkList *tList = NULL;
    LinkListNode *current = NULL;
    int i = 0;

    tList = (TLinkList*)list;

    // 过滤非法参数
    if (list == NULL || pos < 0)
    {
        return -1;
    }

    /* 
     * 插入要点
     *1.让新插入的元素节点指向原有位置的元素节点
     *2.修改原有位置的前一个元素节点的指向(更新指向为新插入的元素节点)
     */

    // 准备环境让辅助指针变量 指向链表头节点
    current = &tList->header;
    // 将当前链表的节点移动到待插入节点的前一个节点的位置(假如待插入的位置是3,则移动到2号位置)
    for (i = 0; i < pos && (current->next != NULL); i++)
    {
        current = current->next; // 将辅助节点运动到指定位置(待插入位置的前一个节点)
    }
    // 让新插入的元素节点指向原有位置的元素节点
    node->next = current->next;
    current->next = node;
    tList->length++;

    return 0;
}

LinkListNode* LinkList_Get(LinkList *list, int pos)
{
    TLinkList *tList = NULL;
    int i = 0;
    LinkListNode *current = NULL;
    LinkListNode *ret = NULL;


    tList = (TLinkList *)list;
    // 过滤非法参数
    if (list == NULL || pos < 0 || pos >= tList->length)
    {
        return NULL;
    }

    
    current = &tList->header;
    // 将辅助指针变量运行到待获取元素的前一个节点
    for (i = 0; i < pos && (current->next != NULL); i++)
    {
        current = current->next;
    }

    ret = current->next;
    return ret;
}



LinkListNode* ListList_Delete(LinkList *list, int pos)
{

    TLinkList *tList = NULL;
    tList = (TLinkList *)list;
    LinkListNode *current = NULL;
    LinkListNode *ret = NULL;
    int i = 0;

    // 过滤非法参数
    if (list == NULL || pos < 0 || pos >= tList->length)
    {
        return NULL;
    }

    // 移动辅助指针变量
    current = &tList->header;
    for (i = 0; i < pos && (current->next != NULL); i++)
    {
        current = current->next;
    }
    ret = current->next;
    
    // 将待删除位置的前一个节点的指向连接到删除位置节点的指向
    current->next = ret->next;
    // 将链表长度-1
    tList->length--;

    return ret;
}

linkqueue.h

#ifndef __MY_LINK_QUEUE_H__
#define __MY_LINK_QUEUE_H__



typedef void LinkQueue;

// 创建队列
LinkQueue* LinkQueue_Create();

// 销毁队列
void LinkQueue_Destroy(LinkQueue* queue);

// 清空队列
void LinkQueue_Clear(LinkQueue* queue);

// 向队尾添加元素
int LinkQueue_Append(LinkQueue* queue, void* item);

// 删除队首元素
void* LinkQueue_Retrieve(LinkQueue* queue);

// 获取队首元素
void* LinkQueue_Header(LinkQueue* header);

// 获取当前队列长度
int LinkQueue_Length(LinkQueue* queue);



#endif

linkqueue.c

#include <stdlib.h>
#include <string.h>

#include "linkqueue.h"
#include "linklist.h"


typedef struct _tag_LinkQueueNode
{
    LinkListNode node;
    void *item;
}TLinkQueueNode;



// 创建队列
LinkQueue* LinkQueue_Create()
{
    return LinkList_Create();
}

// 销毁队列
void LinkQueue_Destroy(LinkQueue* queue)
{
    LinkQueue_Clear(queue);
    LinkList_Destroy(queue);
}

// 清空队列
void LinkQueue_Clear(LinkQueue* queue)
{
    while (LinkQueue_Length(queue) > 0)
    {
        LinkQueue_Retrieve(queue);     // 该函数包含内存释放函数
    }
}

// 向队列中添加元素,相当于向队列的队尾添加元素
int LinkQueue_Append(LinkQueue* queue, void* item)
{
    int ret = 0;
    TLinkQueueNode *node = NULL;
    node = (TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));
    if (node == NULL) return -1;
    memset(node, 0, sizeof(TLinkQueueNode));
    node->item = item;

    ret = LinkList_Insert(queue, (LinkListNode *)node, LinkList_Length(queue));
    if (ret != 0) // 插入失败
    {
        free(node);
        return ret;
    }
    return ret;
}

// 删除队首元素
void* LinkQueue_Retrieve(LinkQueue* queue)
{
    void *ret = NULL;
    TLinkQueueNode *node = NULL;
    node = (TLinkQueueNode*)ListList_Delete(queue, 0);
    if (node == NULL) return NULL;

    ret = node->item;
    free(node);
    node = NULL;
    return ret;
}

// 获取队首元素
void* LinkQueue_Header(LinkQueue* queue)
{
    void *ret = NULL;
    TLinkQueueNode *node = NULL;
    node = (TLinkQueueNode*)LinkList_Get(queue, 0);
    if (node == NULL) return NULL;

    ret = node->item;
    return ret;
}

// 获取当前队列长度
int LinkQueue_Length(LinkQueue* queue)
{
    return LinkList_Length(queue);
}

test.c

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

#include "linkqueue.h"


typedef struct _Student
{
    char name[20];
    int age;
}Student;



int main()
{
    Student s1, s2, s3, s4, s5, s6;
    s1.age = 11;
    s2.age = 12;
    s3.age = 13;
    s4.age = 14;
    s5.age = 15;
    s6.age = 16;


    LinkQueue *queue = LinkQueue_Create();
    if (queue != NULL)
    {
        LinkQueue_Append(queue, &s1);
        LinkQueue_Append(queue, &s2);
        LinkQueue_Append(queue, &s3);
        LinkQueue_Append(queue, &s4);
        LinkQueue_Append(queue, &s5);
        LinkQueue_Append(queue, &s6);
        
        printf("current queue length is: %d\\n",LinkQueue_Length(queue));
        printf("\\n");
        
        // 移除队首元素
        LinkQueue_Retrieve(queue);
        Student *pStu = LinkQueue_Header(queue);
        printf("current header age is %d\\n", pStu->age);
        printf("\\n");
        
        // 清空队列
        LinkQueue_Clear(queue);
        int new_length = LinkQueue_Length(queue);
        printf("currnet queue new length is: %d\\n",new_length);

    }

    system("pause");
    return 0;
}

运行结果:

current queue length is: 6

current header age is 12

currnet queue new length is: 0
请按任意键继续. . .

 

以上是关于5.队列的主要内容,如果未能解决你的问题,请参考以下文章

是否需要锁定阅读对象?

VSCode自定义代码片段5——HTML元素结构

VSCode自定义代码片段5——HTML元素结构

VSCode自定义代码片段5——HTML元素结构

perl中的队列

以下代码片段是不是容易受到 Rails 5 中 SQL 注入的影响?