数据结构——链式队列

        链式队列的组织形式与链表没有什么不同,只不过插入、删除被约束在固定的两端。为了便于操作,通常也会创建管理结构体,用来存储队头指针、队尾指针、队列元素个数等信息。

图解:

        由图可以看到,链式队列主要控制队头和队尾,由于管理结构体中保存了当前队列元素个数size,因此可以不用设计链表的头节点,初始化空队列的时候,只需要让队头、队尾指针同时指向空即可。

一、链式队列的管理结构体设计

图解:

示例代码:

// 链式队列节点设计
typedef struct node
{
    // 数据域
    int data;    

    // 指针域
    struct node *next_p;

}node_t, *node_p;

// 链式队列管理结构体设计
typedef struct link_queue
{
    node_p front_p;    // 队头指针
    node_p rear_p;     // 队尾指针
    int    size;       // 队列当前元素个数

}link_queue_t, *link_queue_p;

二、初始化链式队列

图解:

示例代码:

/**
 * @brief    初始化链式队列
 * @note     None
 * @param    None
 * @retval   成功:返回指向这个链式队列的管理结构体的指针
 *           失败:返回NULL
 */ 
link_queue_p LINK_QUEUE_Init(void) 
{
    // 1、申请堆内存空间
    link_queue_p p = malloc( sizeof( link_queue_t ) );
    bzero( p, sizeof( link_queue_t ) );

    // 2、申请成功,给堆内存空间进行赋值(里面还要申请头节点空间)
    if ( p != NULL)
    {
        // a、申请头节点内存
        node_p head_node = malloc( sizeof( node_t ) );
        bzero( head_node, sizeof( node_t ) );
        if ( head_node != NULL)
        {
            // 数据域无需赋值操作

            // 指针域
            head_node->next_p = NULL;

        }
        else
        {
            free(p);
            return NULL;

        }

        // b、将链式队列的队头和队尾指针,指向头节点的下一个
        p->front_p = head_node;
        p->rear_p  = head_node;

        // c、链式队列的元素个数
        p->size = 0 ;
        
    }
    else
        return NULL;
    
    // 3、成功返回指向这个链式队列管理结构体的指针
    return p;

}

三、初始化数据节点、入队 --- 插入数据(头插法、尾插法)

图解:

1. 头插法

2. 尾插法

示例代码:

/**
 * @brief    入队
 * @note     初始化数据节点、入队(头插法、尾插法)
 * @param    p:       指向这个链式队列的管理结构体的指针
 *           new_data:要插入的数据
 * @retval   成功:返回0
 *           失败:返回非0
 */ 
int LINK_QUEUE_EnQueue( link_queue_p p, int new_data ) 
{
    // 1、创建数据节点
    node_p new_node = malloc( sizeof( node_t ) );
    bzero( new_node, sizeof( node_t ) );
    if ( new_node != NULL )
    {
        // 数据域:
        new_node->data   = new_data;

        // 指针域:
        new_node->next_p = NULL;

    }
    else
        return -1;

    // 2、判断链式队列的头节点的next_p是否为NULL
    if ( p->front_p->next_p == NULL )
    {
        // 头插法
        p->front_p->next_p = new_node;
        new_node->next_p   = NULL;

    }
    
    else
    {   
        // 尾插法
        p->rear_p->next_p = new_node;
        new_node->next_p  = NULL;

    }

    // 让队尾指针指向最后一个数据节点
    p->rear_p = new_node;

    // 3、当前链式队列的数据+1
    p->size++;

    // 4、成功返回0
    return 0;

}

四、判断链表是否为空

示例代码:

/**
 * @brief    判断链式队列是否为空
 * @note     None
 * @param    p:指向这个链式队列的管理结构体的指针
 * @retval   如果队列内存为空:  返回true
 *               队列内存为非空:返回false
 */ 
bool LINK_QUEUE_IfEmpty( link_queue_p p ) 
{
    return ( p->size == 0 );
}

五、遍历整个队列

图解:

示例代码:

/**
 * @brief    遍历整个链式队列数据 
 * @note     None
 * @param    p: 指向这个链式队列的管理结构体的指针
 * @retval   成功:返回0
 *           失败:返回非0
 */ 
int LINK_QUEUE_ShowQueue( link_queue_p p ) 
{
    // 1、判断链式队列数据是否为空
    if ( LINK_QUEUE_IfEmpty(p) )
        return -1;

    // 2、遍历整个链式队列
    node_p tmp_p = NULL;
    int    i     = 0;
    printf("================链式队列里的数据===============\n\n");
    for (tmp_p = p->front_p->next_p, i = 0; tmp_p != NULL; tmp_p = tmp_p->next_p, i++)
    {
        printf("sq_queue[%d] = %d\n", i, tmp_p->data);
    }

    printf("==============================================\n\n");

    // 3、成功返回0
    return 0;

}

六、出队 --- 删除数据

图解:

示例代码:

/**
 * @brief    出队
 * @note     None
 * @param    p:指向这个链式队列的管理结构体的指针
 * @retval   成功:返回0
 *           失败:返回非0
 */ 
int LINK_QUEUE_OutQueue( link_queue_p p ) 
{
    // 1、判断链式队列是否为空
    if ( LINK_QUEUE_IfEmpty(p) )
        return -1;

    // 2、将队头数据节点( p.front_p的next_p )给删除
    node_p last_node  = p->front_p;  
    node_p del_node   = last_node->next_p; 
    node_p next_node  = del_node->next_p;
    
    last_node->next_p = next_node;
    free(del_node);

    // 3、链式队列的数据节点个数减-
    p->size--;

    // 4、成功返回0
    return 0;

}

七、查询数据

图解:

示例代码:

/**
 * @brief    取队头
 * @note     None
 * @param    p: 指向这个链式队列的管理结构体的指针
 * @retval   成功:返回0
 *           失败:返回非0
 */ 
int* LINK_QUEUE_GetFrontData( link_queue_p p ) 
{
    // 1、判断链式队列是否为空
    if ( LINK_QUEUE_IfEmpty(p) )
        return -1;

    // 2、返回链式队列的队头的数据节点的指针
    return &( p->front_p->next_p->data );
}

八、销毁整个队列

图解:

示例代码:

/**
 * @brief    销毁链式队列
 * @note     None
 * @param    p: 指向这个链式队列管理结构体的指针
 * @retval   None
 */ 
void LINK_QUEUE_UnInit( link_queue_p p ) 
{
    // 1、将队头数据节点( p.front_p的next_p )给删除
    node_p last_node  = p->front_p;  
    node_p del_node   = last_node->next_p; 
    node_p next_node  = del_node->next_p;
    node_p tmp_p = NULL;
    
    for ( tmp_p = last_node;  tmp_p->next_p != NULL; tmp_p = tmp_p->next_p ) 
    {
        // a、删除节点并释放其内存
        last_node->next_p  = next_node;
        free( del_node );

        // b、轮回继续
        del_node  = next_node;
        next_node = next_node->next_p;
    }

    if ( tmp_p->next_p == NULL )            // 最后还有一个数据节点,也将其删除并释放了
    {
        last_node->next_p  = next_node;
        free( del_node );
    }
    

    // 2、释放头节点和链式队列的管理结构体
    free(last_node);
    free(p);

}

以上知识就是我的课后笔记了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值