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的实现