栈和队列

1. 栈

  特点: LIFO(Last In First Out)

  应用: 表达式求值, 行编辑, 迷宫求解

// updated 2013-07-15

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

typedef unsigned char u_char_32;
typedef unsigned int  u_int_32;

struct kfifo {
    u_char_32   *buffer;    // the buffer holding the data
    u_int_32    size;       // the size of the allocated buffer
    u_int_32    in;         // the start offset of free section
    u_int_32    out;        // the end offset of data section
};

struct queue {
    struct kfifo fifo;
    int (* queue_init)(struct queue *);
    int (* queue_destroy)(struct queue *);
    int (* queue_clear)(struct queue *);
    int (* queue_empty)(struct queue *);
    u_int_32 (* queue_length)(struct queue *);
    // get data from the head of queue, but 
    // not remove it from the queue.
    int (* queue_peek)(struct queue *, void *, int);
    // put data at the end of queue
    int (* queue_put)(struct queue *, void *, int);
    // get data from the head of queue, and
    // remove it from the queue
    int (* queue_get)(struct queue *, void *, int);

    struct queue *(* queue_dup)(struct queue *);
    // traverse queue step by step
    void (* queue_traverse)(struct queue *, int, void (*)(void *));

    int (* queue_reverse)(struct queue *);
};


#define min(x, y)   ((x) > (y) ? (y) : (x))
#define swap(x, y)  ({  \
    int __tmp = x;  \
    x = y;  \
    y = __tmp;  \
})

#define QUEUE_MAX_SIZE  1024

static void _kfifo_init(struct kfifo *fifo, u_char_32 *buffer, u_int_32 size)
{
    fifo->buffer = buffer;
    fifo->size = size;
    fifo->in = 0;
    fifo->out = 0;
}

static int _kfifo_alloc(struct kfifo *fifo, u_int_32 size)
{
    u_char_32 *buffer = (u_char_32 *)malloc(size);
    if ( !buffer ) {
        _kfifo_init(fifo, NULL, 0);
        return 1;
    }

    _kfifo_init(fifo, buffer, size);
    return 0;
}

static int _M_queue_init(struct queue *q)
{
    if ( !q ) 
        return 1;   // error

    return _kfifo_alloc(&(q->fifo), QUEUE_MAX_SIZE);
}

void _kfifo_free(struct kfifo *fifo)
{
    free(fifo->buffer);
    free(fifo);
}

static int _M_queue_clear(struct queue *q)
{
    if ( !q )
        return 1;   // error

    if ( q->fifo.buffer ) {
        free(q->fifo.buffer);
        q->fifo.in = 0;
        q->fifo.out = 0;
        q->fifo.size = 0;
    }

    return 0;
}

static int _M_queue_destroy(struct queue *q)
{
    if ( !q )
        return 1;   // error

    if ( !q->queue_clear(q) )
        free(q);
    else
        return 1;

    return 0;
}

static int _kfifo_empty(struct kfifo *fifo)
{
    return (fifo->out == fifo->in);
}

static int _M_queue_empty(struct queue *q)
{
    if ( !q )
        return -1;

    return _kfifo_empty(&(q->fifo));
}

static u_int_32 _kfifo_rest(struct kfifo *fifo)
{
    return (fifo->size - fifo->in + fifo->out);
}

static u_int_32 _kfifo_data_size(struct kfifo *fifo)
{
    if ( fifo->in < fifo->out )
        return (fifo->size - fifo->out + fifo->in);
    else
        return (fifo->in - fifo->out);
}

static u_int_32 _M_queue_length(struct queue *q)
{
    if ( !q )
        return -1;   // error

    return _kfifo_data_size(&(q->fifo));
}

static int _kfifo_full(struct kfifo *fifo)
{
    return (_kfifo_rest(fifo) == 0);
}


static int _kfifo_put_data(struct kfifo *fifo, u_char_32 *buffer, u_int_32 len)
{
    if ( _kfifo_rest(fifo) < len )
        return 1;   // fifo is not enough to store data


//
//         out
//          |                    +---------+
//          V                   /           \---> first
//  +-------+------------------+-------------+
//  | free  |       data       |    free     |
//  +-------+------------------+-------------+
//                             ^
//                             |
//                            in 
//
//    u_int_32 section = min(len, (fifo->size - (fifo->in & (fifo->size - 1))));
    u_int_32 first = min(len, fifo->size - fifo->in);
    memcpy(fifo->buffer + fifo->in, buffer, first);
    fifo->in += first;

    if ( len - first > 0 ) {
//
//  in     out
//  |       |                    
//  V       V                   
//  +-------+------------------+-------------+
//  | free  |       data       |   new data  |
//  +-------+------------------+-------------+
//  \       /--> second        
//   +-----+                   
//                             
//
        u_int_32 second = len - first;
        memcpy(fifo->buffer, buffer+first, second);
        fifo->in = second;
    }
    
    return 0;
}

int _M_queue_put(struct queue *q, void *buffer, int size)
{
    if ( !q || !buffer )
        return 1;

    return _kfifo_put_data(&(q->fifo), (u_char_32 *)buffer, (u_int_32)size);
}


int _kfifo_get_data(struct kfifo *fifo, u_char_32 *buffer, u_int_32 len)
{
    if ( _kfifo_data_size(fifo) < len )
        return 1;
    
//
//          in
//          |                    +---------+
//          V                   /           \---> first
//  +-------+------------------+-------------+
//  | data  |       free       |    data     |
//  +-------+------------------+-------------+
//                             ^
//                             |
//                            out
//
//    u_int_32 section = min(len, (fifo->size - (fifo->in & (fifo->size - 1))));
    u_int_32 first = min(len, fifo->size - fifo->out);
    memcpy(buffer, fifo->buffer + fifo->out, first);
    fifo->out += first;

    if ( len - first > 0 ) {
//
// out      in
//  |       |                    
//  V       V                   
//  +-------+------------------+-------------+
//  | data  |       free       |    free     |
//  +-------+------------------+-------------+
//  \       /--> second        
//   +-----+                   
//                            
//
        u_int_32 second = len - first;
        memcpy(buffer+first, fifo->buffer, second);
        fifo->out = second;
    }
    
    return 0;
}

static int _M_queue_get(struct queue *q, void *buffer, int size)
{
    if ( !q )
        return 1;

    // if buffer is NULL, delete the head data
    if ( !buffer ) {
        if ( (u_int_32)size > _kfifo_data_size(&(q->fifo)) )
            return 1;

        u_int_32 len = min((u_int_32)size, q->fifo.size - q->fifo.out);
        if ( (u_int_32)size > len )
            q->fifo.out = (u_int_32)size - len;
        else
            q->fifo.out += len;
    } else {
        _kfifo_get_data(&(q->fifo), (u_char_32 *)buffer, (u_int_32)size);
    }

    return 0;
}

int _kfifo_peek_data(struct kfifo *fifo, u_char_32 *buffer, u_int_32 len)
{
    if ( _kfifo_data_size(fifo) < len )
        return 1;
    
//
//          in
//          |                    +---------+
//          V                   /           \---> first
//  +-------+------------------+-------------+
//  | data  |       free       |    data     |
//  +-------+------------------+-------------+
//                             ^
//                             |
//                            out
//

    u_int_32 first = min(len, fifo->size - fifo->out);
    memcpy(buffer, fifo->buffer + fifo->out, first);

    if ( len - first > 0 ) {
//
//         in
//          |                    
//          V                   
//  +-------+------------------+-------------+
//  | data  |       free       |    data     |
//  +-------+------------------+-------------+
//  \       /--> second        ^
//   +-----+                   |
//                            out
//
        u_int_32 second = len - first;
        memcpy(buffer+first, fifo->buffer, second);
    }
    
    return 0;
}

static int _M_queue_peek(struct queue *q, void *buffer, int size)
{
    if ( !q || !buffer )
        return 1;

    return _kfifo_peek_data(&(q->fifo), (u_char_32 *)buffer, (u_int_32)size);
}

static struct queue *_M_queue_dup(struct queue *q)
{
    struct queue *dup = NULL;
    dup = (struct queue *)malloc(sizeof(struct queue));
    if ( !dup )
        return dup;
    
    queue_register(dup);
    if ( dup->queue_init(dup) ) {
        free(dup);
        return NULL;
    }

    memcpy(dup->fifo.buffer, q->fifo.buffer, dup->fifo.size);
    dup->fifo.in = q->fifo.in;
    dup->fifo.out = q->fifo.out;

    return dup;
}

/*
static int _kfifo_reverse(struct kfifo *fifo)
{
    if ( _kfifo_data_size(fifo) <= 0 )
        return 1;
    u_int_32 len = _kfifo_data_size(fifo);
    u_char_32 *buf = (u_char_32 *)malloc(len);
    if ( !buf )
        return 1;
    if ( fifo->in > fifo->out ) {
        u_int_32 half = len/2;
        u_int_32 rest = len - half;
        memcpy(buf, fifo->buffer + fifo->out, half);
        memcpy(fifo->buffer + fifo->out, 
                    fifo->buffer + fifo->out + rest, half);
        memcpy(fifo->buffer + fifo->out + rest, buf, half);
    } else {
        u_int_32 half = len/2;
        u_int_32 rest = len - half;
        memcpy(buf, fifo->buffer + fifo->out, len);
        u_char_32 tmp[QUEUE_MAX_SIZE];
        memcpy(tmp, buf, half);
        memcpy(buf, buf+rest, half);
        memcpy(buf+rest, tmp, half);

        // copy to fifo->buffer
        half = fifo->size - fifo->out;
        memcpy(fifo->buffer + fifo->out, buf, half);
        memcpy(fifo->buffer, buf + half, len - half);
    }

    free(buf);
    return 0;
}
*/
static int _kfifo_reverse(struct kfifo *fifo)
{
    if ( _kfifo_data_size(fifo) <= 0 )
        return 1;
    u_int_32 len = _kfifo_data_size(fifo)/4;
    u_int_32 i;
    u_int_32 out = fifo->out;
    u_int_32 in = fifo->in;
    
    if ( fifo->size-out > len*4 ) {
        
        //
        //
        //         out  
        //          | 
        //          V
        //  +-------+--------+---------+-------------+
        //  | free  |  1234  |   5678  |    free     |
        //  +-------+--------+---------+-------------+
        //                             ^
        //                             |
        //                            in 
        //
        //         out  
        //          | 
        //          V
        //  +-------+---------+--------+-------------+
        //  | free  |  8765   |  4321  |    free     |
        //  +-------+---------+--------+-------------+
        //                             ^
        //                             |
        //                            in 
        //
        
        for ( i = 0; i < len/2; i++ ) {
            in -= 4;
            swap(*(u_int_32 *)(fifo->buffer + out), *(u_int_32 *)(fifo->buffer + in));
            out += 4;
        }
    } else {
        
        //
        //
        //          in  
        //          |                 
        //          V                
        //  +-------+------------------+----------+--+
        //  |  678  |       free       |  1234    |5 |
        //  +-------+------------------+----------+--+
        //  |       |                 /^            /
        //  |       |                / |           /
        //  |       | +-------------+ out         /
        //  |       |/             +-------------+
        //  |       |             /
        //  +--------+----------+
        //  |  12345 |   678    |
        //  +--------+----------+
        //
        //
        //          in  
        //          |                 
        //          V                
        //  +-------+------------------+-------------+
        //  | 321   |       free       |    87654    |
        //  +-------+------------------+-------------+
        //  |       |                 /^            /
        //  |       |                / |           /
        //  |       | +-------------+ out         /
        //  |       |/             +-------------+
        //  |       |             /
        //  +---------+---------+
        //  |   87654 |  321    |
        //  +---------+---------+
        
        u_int_32 min_len = min(len/2, (fifo->size - out)/4);
        for ( i = 0; i < min_len; i++ ) {
            in -= 4;
            if ( in < 0 )
                in = fifo->size - 4;
            swap(*(u_int_32 *)(fifo->buffer + out), *(u_int_32 *)(fifo->buffer + in));
            out += 4;
        }

        if ( min_len - len/2 > 0 ) {
            out = 0;
            for ( i = 0; i < min_len - len/2; i++ ) {
                in -= 4;
                swap(*(u_int_32 *)(fifo->buffer + out), *(u_int_32 *)(fifo->buffer + in));
                out += 4;
            }
        }
    }

    return 0;
}

static int _M_queue_reverse(struct queue *q)
{
    if ( !q )
        return 1;

    return _kfifo_reverse(&(q->fifo));
}

static void _M_visit(void *buffer)
{
    printf("visit address %p\n", buffer);
}

static void _M_queue_traverse(struct queue *q, int step, void (*visit)(void *))
{
    if ( !q || !visit || !step )
        return ;

    struct queue *dup = q->queue_dup(q);
    if ( !dup )
        return ;

    if ( step > 0 ) {
        // forward
        u_char_32 *buffer = (u_char_32 *)malloc(step);
        while ( !dup->queue_empty(dup) ) {
            dup->queue_get(dup, buffer, (u_int_32)step);
            visit((void *)buffer);
        }
    } else {
        // backward
        u_int_32 size = -step;
        u_char_32 *buffer = (u_char_32 *)malloc(size);
        if ( dup->queue_reverse(dup) ) 
            goto end;
        while ( !dup->queue_empty(dup) ) {
            dup->queue_get(dup, buffer, (u_int_32)size);
            visit((void *)buffer);
        }
    }

end: 
    dup->queue_destroy(dup);
}

int queue_register(struct queue *q)
{
    if ( !q )
        return 1;

    q->queue_init = _M_queue_init;
    q->queue_destroy = _M_queue_destroy;
    q->queue_clear = _M_queue_clear;
    q->queue_empty = _M_queue_empty;
    q->queue_length = _M_queue_length;
    q->queue_peek = _M_queue_peek;
    q->queue_get = _M_queue_get;
    q->queue_put = _M_queue_put;
    q->queue_dup = _M_queue_dup;
    q->queue_traverse = _M_queue_traverse;
    q->queue_reverse = _M_queue_reverse;
}

static void _M_visit_int(void *buffer)
{
    printf("visit %d\n", *(int *)buffer);
}

int testdata[] = {1, 1, 2, 3, 5, 8, 13, 21, 33, 54, 87};

int main()
{
    struct queue squeue;
    queue_register(&squeue);

    squeue.queue_init(&squeue);

    int len = sizeof(testdata)/sizeof(testdata[0]);
    int i;
    for ( i = 0; i < len; i++ ) {
        squeue.queue_put(&squeue, &(testdata[i]), sizeof(testdata[i]));
    }

//    squeue.queue_traverse(&squeue, sizeof(int), _M_visit_int);
    squeue.queue_traverse(&squeue, -4, _M_visit_int);

    int buffer = 0;
    for ( i = 0; i < len; i++ ) {
        squeue.queue_get(&squeue, &buffer, sizeof(buffer));
        printf("%d\n", buffer);
    }

    squeue.queue_clear(&squeue);
    return 0;
}

先贴个写了一半的代码

借鉴了linux kernel kfifo的实现






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值