以链表为基础实现链式队列——————遍历、入队、出队 (基于C语言实现)

以链表为基础实现链式队列

​ 如果打算以链表作为基础来实现队列的操作,可以避免内存浪费以及避免内存成片移动,只需要确定队头和队尾即可,一般把链表头部作为队头,可以实现头删,把链表尾部作为队尾,可以实现尾插。

​ 需要注意的点:

  • 遍历队列需要备份地址
  • 出队需要考虑空列表、列表中只有一个数据的情况

image

下面是我的函数接口:

定义链式队列中的元素的数据类型

// 指的是链式队列中的元素的数据类型,用户可以根据需要进行修改
typedef int DataType_t;

创建链式队列的结构体类型

// 构造记录链式队列结点linkrqueuenode各项参数(指针域next+数据域data)
typedef struct LinkrQueueNode
{
    DataType_t data;             // 数据域
    struct LinkrQueueNode *next; // 指针域
} LinkrQueueNode_t

创建管理链式队列的结构体类型(队首+队尾)

// 构造记录链式队列linkrqueue各项参数(队列的队头+队尾)的结构体
typedef struct LinkrQueue
{
    LinkrQueueNode_t *Rear;  // 队首,记录头结点地址
    LinkrQueueNode_t *Front; // 队尾,记录尾结点地址

} LinkrQueue_t;

创建一个链式队列,并对其初始化

/******************************************************
 *
 *  name      : Linkqueue_Create
 *	function  : 创建一个链式队列,并对其初始化
 *  argument  :None
 *  retval    : 链式队列记录者的地址
 *  author    : Dazz
 *  date      : 2024/4/26
 *  note      : None
 *
 * *******************************************************/
LinkrQueue_t *LinkQueue_Create(void)
{

    // 创建记录链式队列的结构体,并对其初始化
    LinkrQueue_t *record = (LinkrQueue_t *)calloc(1, sizeof(LinkrQueue_t));

    // 判断链式队列的记录者是否申请成功
    if (NULL == record)
    {
        printf("The link queue application failed!\n");
        exit(-1); // 程序异常终止
    }

    // 对链式队列的记录者进行初始化
    record->Front = NULL;
    record->Rear = NULL;

    return record;
}

判断链式队列是否为空

/******************************************************
 *
 *  name      : Linkqueue_Create
 *	function  : 判断链式队列是否为空
 *  argument  :None
 *  retval    : 队链为空返回1,否则返回0
 *  author    : Dazz
 *  date      : 2024/4/26
 *  note      : None
 *
 * *******************************************************/
bool LinkQueue_IsEmpty(LinkrQueue_t *record)
{
    return ((record->Front == NULL) && (record->Rear == NULL)) ? true : false;
}

创建一个新的结点,并对该结点进行初始化(数据域 + 指针域)

/******************************************************
 *
 *  name      : LinkQueueNode_Create
 *	function  : 创建一个新的结点,并对该结点进行初始化(数据域 + 指针域)
 *  argument
 * 				@data :需要传入结点中的数据
 *
 *  retval    : 新结点的地址
 *  author    : Dazz
 *  date      : 2024/4/26
 *  note      : None
 *
 * *******************************************************/
LinkrQueueNode_t *LinkQueueNode_Create(DataType_t data)
{
    // 创建新的结点
    LinkrQueueNode_t *New = (LinkrQueueNode_t *)calloc(1, sizeof(LinkrQueueNode_t));

    // 判断是否创建成功
    if (NULL == New)
    {
        printf("The new node creation failed\n");
        return;
    }

    // 对新结点初始化
    New->next = NULL;
    New->data = data;

    return New;
}

将结点入队

/******************************************************
 *
 *  name      : Linkqueue_Enqueue
 *	function  : 将结点入队
 *  argument
 *              @record :链式队列记录者的地址
 *              @data   :结点数据域里的数据
 *
 *  retval    : 成功返回1,否则为0
 *  author    : Dazz
 *  date      : 2024/4/26
 *  note      : None
 *
 * *******************************************************/
bool Linkqueue_Enqueue(LinkrQueue_t *record, DataType_t data)
{
    // 创建新结点
    LinkrQueueNode_t *New = LinkQueueNode_Create(data);

    // 判断新结点是否创建成功
    if (NULL == New)
        return false;

    if (LinkQueue_IsEmpty(record)) // 链队为空的情况
    {
        record->Front = New; // 链队记录者的Front指向新结点
        record->Rear = New;  // 链队记录者的Rear指向新结点
    }
    else // 链队不为空的情况
    {
        record->Rear->next = New; // 将尾结点的指针域指向新结点
        record->Rear = New;       // 将管理者的Rear指向新结点
    }
    return true;
}

遍历链队,打印每个结点中的数据

/******************************************************
 *
 *  name      : PrintfAllNodes
 *	function  : 遍历链队,打印每个结点中的数据
 *  argument
 * 				@record :记录者的地址
 *
 *  retval    : None
 *  author    : Dazz
 *  date      : 2024/4/24
 *  note      : None
 *
 * *******************************************************/
void PrintfAllNodes(LinkrQueue_t *record)
{
    // 判断队列是否为空,如为空,直接退出
    if (LinkQueue_IsEmpty(record))
    {
        printf("The queue is empty\n");
        return;
    }

    // 对记录者的rear进行备份
    LinkrQueueNode_t *temp = record->Front;

    // 用循环遍历链队
    while (temp->next != NULL)
    {
        printf("%d\n", temp->data);
        temp = temp->next;
    }
    printf("%d\n", temp->data);
}

将链队出队

/******************************************************
 *
 *  name      : LinkQueue_Dequeue
 *	function  : 将链队出队
 *  argument
 * 				@record :记录者的地址
 *
 *  retval    : 出队的数据
 *  author    : Dazz
 *  date      : 2024/4/24
 *  note      : None
 *
 * *******************************************************/
DataType_t LinkQueue_Dequeue(LinkrQueue_t *record)
{
    // 定义变量记录要出队的数据
    DataType_t temp = 0;

    // 判断链队是否为空
    if (LinkQueue_IsEmpty(record))
    {
        printf("The queue is empty and cannot be dequeued\n");
        return;
    }
    // 队列只有一个结点的情况
    else if (NULL == record->Front->next)
    {
        temp = record->Front->data;             // 对要出队的数据进行备份
        LinkrQueueNode_t *temp = record->Front; // 对要出队的地址进行备份
        record->Front = NULL;                   // 重新把记录器的Front指向NULL
        record->Rear = NULL;                    // 重新把记录器的Rear指向NULL
        free(temp);                             // 释放要出队的结点
    }
    else
    {
        // 队列不为空的情况,数据需从队首出队
        temp = record->Front->data;                 // 对要出队的数据进行备份
        LinkrQueueNode_t *nodetemp = record->Front; // 对要出队的地址进行备份
        record->Front = nodetemp->next;             // 将记录者的Front指向出队结点的后面的结点
        nodetemp->next = NULL;                      // 将要出对的结点的指针域指向NULL
        free(nodetemp);                             // 释放要出队的结点
    }

    return temp;
}
posted @ 2024-04-26 23:57  Dazz_24  阅读(160)  评论(0)    收藏  举报