数据结构:通用队列

队列

队列和链表比较类似 不同之处在于队列仅允许从队列头部(front)删除节点 
                                  从队列尾部(rear)增加节点 
可以将队列看作是栈的反例
队列:先入先出(FIFO)
栈:先入后出(LIFO)

前文已经分析过栈的原理:
http://blog.csdn.net/qq_21358401/article/details/79348642

侵入式队列

侵入式结构用来实现通用数据结构的例子已经分析过很多遍了 好处就是通用.

队列和链表一样 每一个节点应该能够访问前后的节点 
so..
struct queue {
    struct queue *prev;
    struct queue *next;
};

初始化队列:
#define INIT_QUEUE(front,rear) \
    {(front)->next = (rear);\
     (front)->prev = NULL;\
     (rear)->next = NULL;\
     (rear)->prev = (front);}

判断是否为空队列:
static inline int queue_empty(struct queue *front, struct queue *rear) {
    return front->next == rear && rear->prev == front;
}

入队:
static inline void enqueue(struct queue *rear, struct queue *new_node) {
    assert(rear != NULL);
    assert(new_node != NULL);

    // 改变rear和rear->prev的指向关系
    new_node->next = rear;
    new_node->prev = rear->prev;
    rear->prev->next = new_node; // 插入新节点
    rear->prev = new_node;
}

出队:
static inline struct queue * _dequeue(struct queue *front, struct queue *rear) {
    assert(front != NULL);
    struct queue *tmp = NULL;

    tmp = front->next;
    if (queue_empty(front, rear)) {
        return NULL;
    } else {
        front->next = tmp->next; // 改变front和front->next的指向
        tmp->next->prev = front;
    }

    return tmp;
}
出队操作的是queue结构节点 还应该增加对应的包装结构的出队
#define queu_entry(ptr,type,member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define dequeue(front,rear,type,member) queue_entry(_dequeue(front,rear),type,member)

示例代码

//
// Created by mac on 2018/2/22.
//

#ifndef CODINGUTILS_QUEUE_H
#define CODINGUTILS_QUEUE_H

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

struct queue {
    struct queue *next;
    struct queue *prev;
};

#define INIT_QUEUE(front,rear) {(front)->next = (rear);(front)->prev = NULL;(rear)->next = NULL;(rear)->prev = (front);}
#define list_entry(ptr,type,member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define queue_entry(ptr,type,member) list_entry(ptr,type,member)

static inline int queue_empty(struct queue *front, struct queue *rear) {
    return front->next == rear && rear->prev == front;
}

static inline void enqueue(struct queue *rear, struct queue *new_node) {
    assert(rear != NULL);
    assert(new_node != NULL);

    new_node->next = rear;
    new_node->prev = rear->prev;
    rear->prev->next = new_node;
    rear->prev = new_node;
}

static inline struct queue * _dequeue(struct queue *front, struct queue *rear) {
    assert(front != NULL);
    struct queue *tmp = NULL;

    tmp = front->next;
    if (queue_empty(front, rear)) {
        return NULL;
    } else {
        front->next = tmp->next;
        tmp->next->prev = front;
    }

    return tmp;
}

#define dequeue(front,rear,type,member) queue_entry(_dequeue(front,rear),type,member)

#endif //CODINGUTILS_QUEUE_H

//
// Created by mac on 2018/2/22.
//

#include "queue.h"

#define log(fmt,...)\
    do {\
        printf(fmt,##__VA_ARGS__);\
        printf("\n");\
    } while (0)

struct queue_node {
    struct queue node;
    int val;
};

int main() {
    log("queue test");
    struct queue front, rear;
    INIT_QUEUE(&front, &rear);

    int i = 0;
    for (i = 0; i < 5; i++) {
        struct queue_node *tmp = NULL;
        tmp = malloc(sizeof(struct queue_node));
        if (!tmp) {
            log("failed to alloc queue node");
            return -1;
        }

        tmp->val = i;
        enqueue(&rear, &tmp->node);
        log("enqueue node val:%d", tmp->val);
    }

    while (!queue_empty(&front, &rear)) {
        struct queue_node *val = NULL;

        val = dequeue(&front, &rear, struct queue_node, node);
        log("dequeue node val:%d", val->val);

        free(val);
    }

    return 0;
}

git repo:
https://github.com/sliver-chen/codingutil/tree/master/data_struct/queue
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值