C编写的具有模板功能的Vector - 基于动态顺序数组

来源:互联网 发布:广联达预算软件购买 编辑:程序博客网 时间:2024/06/02 06:06

要点:

1. 要通过C来实现类似于C++中的Vector模板,常用的做法是使用typedef,但这么做的话无法实现C++中拷贝函数及析构函数的功能,而且还需要考虑包含头文件的顺序,即目标类型必须先于Vector定义。

2. 故可以考虑使用void  *类型指针。

3. 对于指针来说,重要的不是类型,唯一重要的是这个指针所指向的内存区域中一个元素的大小是多少,如char *指针指向的内存区域一个元素占8位,short *则占16位,对于一些结构体指针来说,这个值可以是任意倍的字节。

4. 对于32位机器来说,每个指针本身的大小都是32位


总结如上要点,得出的解决办法是,

typedef void *vector_entry_ptr;typedef void (*vector_copy_func)(vector_entry_ptr, const vector_entry_ptr);typedef void (*vector_cleanup_func)(vector_entry_ptr);    /* the parameter passed to clean_f is the address of the ith element */typedef struct _vector {    vector_entry_ptr datap;    unsigned long elementSize;    unsigned long capacity;    unsigned long count;    vector_copy_func copy_f;    vector_cleanup_func clean_f;} Vector, *VectorPtr;

声明一个这样的数据结构。

copy_f以及clean_f是函数指针,这里充当拷贝构造函数和析构函数的作用。可以使用memcpy和free作为默认行为(当他们为NULL的时候)。

具体操作见源代码:

vector.h

/* * Dynamic Allocated Array-Based Vector C Implementation * For The Teco Project * Copyright (C) 2010 milkyjing <milkyjing@gmail.com> * Auguest 11th, 2010 * * Modified for The RIXE Project at June 14th, 2011 by milkyjing * * This software is provided 'as-is', without any express or implied * warranty.  In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not *    claim that you wrote the original software. If you use this software *    in a product, an acknowledgment in the product documentation would be *    appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be *    misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * milkyjing * */#ifndef VECTOR_H#define VECTOR_H#pragma once#include <memory.h>#include <stdlib.h>typedef void *vector_entry_ptr;typedef void (*vector_copy_func)(vector_entry_ptr, const vector_entry_ptr);typedef void (*vector_cleanup_func)(vector_entry_ptr);    /* the parameter passed to clean_f is the address of the ith element */typedef struct _vector {    vector_entry_ptr datap;    unsigned long elementSize;    unsigned long capacity;    unsigned long count;    vector_copy_func copy_f;    vector_cleanup_func clean_f;} Vector, *VectorPtr;typedef int (*vector_compare_func)(const vector_entry_ptr, const vector_entry_ptr);  /* (src, key), `> 0' - left larger, `= 0' equal, `< 0', left smaller */typedef int (*vector_compare_interval_func)(const vector_entry_ptr, const vector_entry_ptr, const vector_entry_ptr);  /* (start, end, key), the last parameter is key, `> 0' - key on the left, `= 0' in the interval, `< 0', key on the right */typedef void (*vector_traverse_func)(const vector_entry_ptr);#ifdef __cplusplusextern "C" {#endif    /* __cplusplus */extern void vector_create(VectorPtr *pvptr, unsigned long elementSize, unsigned long elements, vector_copy_func copy_f, vector_cleanup_func clean_f);extern unsigned long vector_get_size(const VectorPtr vptr);extern const vector_entry_ptr vector_get_buf(const VectorPtr vptr);extern int vector_assign(VectorPtr vptr, unsigned long i, const vector_entry_ptr element);/* element can be NULL, if so, we will not make a copy to element. the return value is the address of the element retrieved */extern const vector_entry_ptr vector_retrieve(const VectorPtr vptr, unsigned long i, vector_entry_ptr element);extern void vector_push_back(VectorPtr vptr, const vector_entry_ptr element);extern int vector_pop_back(VectorPtr vptr);extern void vector_clear(VectorPtr vptr);extern void vector_destroy(VectorPtr vptr);/* UTILITY FUNCTIONS */extern void vector_traverse(const VectorPtr vptr, vector_traverse_func traverse_func);extern void vector_bulbsort(VectorPtr vptr, vector_compare_func compare_func);/* s should always be 0, and l should always be vptr->count - 1, note that both s and l should be signed rather than unsigned */extern void vector_quicksort(VectorPtr vptr, long s, long l, vector_compare_func compare_func);/* if element = NULL, it won't copy the result to it, just return the index, which somehow increase performance */extern long vector_sequential_search(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_func compare_func, vector_entry_ptr element);/* if element = NULL, it won't copy the result to it, just return the index, which somehow increase performance */extern long vector_binary_search(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_func compare_func, vector_entry_ptr element);/* returns the left side element (start) */extern long vector_binary_search_interval(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_interval_func compare_interval_func);#ifdef __cplusplus}#endif#endif    /* VECTOR_H */


vector.c
/* *  Copyright (C) 2011 milkyjing <milkyjing@gmail.com> * * This software is provided 'as-is', without any express or implied * warranty.  In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not *    claim that you wrote the original software. If you use this software *    in a product, an acknowledgment in the product documentation would be *    appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be *    misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * milkyjing * */#include "vector.h"void vector_create(VectorPtr *pvptr, unsigned long elementSize, unsigned long elements, vector_copy_func copy_f, vector_cleanup_func clean_f) {    VectorPtr vptr;    vptr = (VectorPtr)malloc(sizeof(Vector));    vptr->elementSize = elementSize;    vptr->capacity = elements;    vptr->count = elements;    vptr->copy_f = copy_f;    /* if copy_f = NULL, default copy function will be applied */    vptr->clean_f = clean_f;  /* if clean_f = NULL, default cleanup function will be applied */    if (elements > 0) {        unsigned long size = vptr->capacity * vptr->elementSize;        vptr->datap = (vector_entry_ptr)malloc(size);        memset(vptr->datap, 0, size);    } else        vptr->datap = NULL;    *pvptr = vptr;}unsigned long vector_get_size(const VectorPtr vptr) {    return vptr->count;}const vector_entry_ptr vector_get_buf(const VectorPtr vptr) {    return (const vector_entry_ptr)vptr->datap;}int vector_assign(VectorPtr vptr, unsigned long i, const vector_entry_ptr element) {    vector_entry_ptr oldElem;    if (i >= vptr->count) return -1;    oldElem = (unsigned char *)vptr->datap + i * vptr->elementSize;    if (vptr->clean_f)        vptr->clean_f(oldElem);    if (vptr->copy_f)        vptr->copy_f(oldElem, element);    else        memcpy(oldElem, element, vptr->elementSize);    return 0;}const vector_entry_ptr vector_retrieve(const VectorPtr vptr, unsigned long i, vector_entry_ptr element) {    vector_entry_ptr oldElem;    if (i >= vptr->count) return NULL;    oldElem = (unsigned char *)vptr->datap + i * vptr->elementSize;    if (element) {  /* make a copy */        if (vptr->copy_f)            vptr->copy_f(element, oldElem);        else            memcpy(element, oldElem, vptr->elementSize);    }    return (const vector_entry_ptr)oldElem;}void vector_push_back(VectorPtr vptr, const vector_entry_ptr element) {    vector_entry_ptr oldElem;    if (vptr->count == vptr->capacity) {        vptr->capacity += vptr->capacity / 2 + 1;        vptr->datap = (vector_entry_ptr)realloc(vptr->datap, vptr->capacity * vptr->elementSize);    }    oldElem = (unsigned char *)vptr->datap + vptr->count * vptr->elementSize;    if (vptr->copy_f)        vptr->copy_f(oldElem, element);    else        memcpy(oldElem, element, vptr->elementSize);    vptr->count++;}int vector_pop_back(VectorPtr vptr) {    vector_entry_ptr oldElem;    if (0 == vptr->count) return -1;    oldElem = (unsigned char *)vptr->datap + (vptr->count - 1) * vptr->elementSize;    if (vptr->clean_f)        vptr->clean_f(oldElem);    vptr->count--;    return 0;}void vector_clear(VectorPtr vptr) {    if (vptr->clean_f) {        unsigned long i;        for (i = 0; i < vptr->count; i++)            vptr->clean_f((unsigned char *)vptr->datap + i * vptr->elementSize);  /* the parameter passed to clean_f is the address of the ith element */    }    free(vptr->datap);    vptr->datap = NULL;    vptr->capacity = 0;    vptr->count = 0;    /* other data members should stay unchanged */}void vector_destroy(VectorPtr vptr) {    vector_clear(vptr);    free(vptr);}/* UTILITY FUNCTIONS */void vector_traverse(const VectorPtr vptr, vector_traverse_func traverse_func) {    unsigned long i;    for (i = 0; i < vptr->count; i++)        traverse_func((unsigned char *)vptr->datap + i * vptr->elementSize);}void vector_bulbsort(VectorPtr vptr, vector_compare_func compare_func) {    unsigned long i, j;    vector_entry_ptr p1, p2, pt;    pt = (vector_entry_ptr)malloc(vptr->elementSize);    /* use as temp */    for (i = 0; i < vptr->count; i++) {        for (j = 0; j < vptr->count - i - 1; j++) {            p1 = (unsigned char *)vptr->datap + j * vptr->elementSize;            p2 = (unsigned char *)p1 + vptr->elementSize;            if (compare_func(p1, p2) > 0) {                memcpy(pt, p1, vptr->elementSize);                memcpy(p1, p2, vptr->elementSize);                memcpy(p2, pt, vptr->elementSize);            }        }    }    free(pt);}/* s should always be 0, and l should always be vptr->count - 1, note that both s and l should be signed rather than unsigned */void vector_quicksort(VectorPtr vptr, long s, long l, vector_compare_func compare_func) {    long i, j;    vector_entry_ptr pt;    i = s;    j = l;    pt = (vector_entry_ptr)malloc(vptr->elementSize);    /* use as temp */    if (s < l) {        memcpy(pt, (unsigned char *)vptr->datap + s * vptr->elementSize, vptr->elementSize);        while (i != j) {            while (j > i && compare_func((unsigned char *)vptr->datap + j * vptr->elementSize, pt) > 0) j--;            memcpy((unsigned char *)vptr->datap + i * vptr->elementSize, (unsigned char *)vptr->datap + j * vptr->elementSize, vptr->elementSize);            while (i < j && compare_func((unsigned char *)vptr->datap + i * vptr->elementSize, pt) < 0) i++;            memcpy((unsigned char *)vptr->datap + j * vptr->elementSize, (unsigned char *)vptr->datap + i * vptr->elementSize, vptr->elementSize);        }        memcpy((unsigned char *)vptr->datap + i * vptr->elementSize, pt, vptr->elementSize);        vector_quicksort(vptr, s, i - 1, compare_func);        vector_quicksort(vptr, i + 1, l, compare_func);    }    free(pt);}long vector_sequential_search(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_func compare_func, vector_entry_ptr element) {    unsigned long i;    vector_entry_ptr temp;    for (i = 0; i < vptr->count; i++) {        temp = (unsigned char *)vptr->datap + i * vptr->elementSize;        if (compare_func(key, temp) == 0) {            if (element) {                if (vptr->copy_f)                    vptr->copy_f(element, temp);                else                    memcpy(element, temp, vptr->elementSize);            }            return i;        }    }    return -1;}long vector_binary_search(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_func compare_func, vector_entry_ptr element) {    long bottom, top, mid;    vector_entry_ptr temp;    bottom = 0;    top = vptr->count - 1;    while (bottom < top) {        mid = (top + bottom) / 2;        temp = (unsigned char *)vptr->datap + mid * vptr->elementSize;        if (compare_func(temp, key) < 0)            bottom = mid + 1;        else            top = mid;    }    temp = (unsigned char *)vptr->datap + top * vptr->elementSize;    if (bottom > top || compare_func(temp, key) != 0) return -1;    if (element) {        if (vptr->copy_f)            vptr->copy_f(element, temp);        else            memcpy(element, temp, vptr->elementSize);    }    return top;}long vector_binary_search_interval(const VectorPtr vptr, const vector_entry_ptr key, vector_compare_interval_func compare_interval_func) {    long bottom, top, mid;    vector_entry_ptr start, end;    bottom = 0;    top = vptr->count - 2;    while (bottom < top) {        mid = (top + bottom) / 2;        start = (unsigned char *)vptr->datap + mid * vptr->elementSize;        end = (unsigned char *)start + vptr->elementSize;        if (compare_interval_func(start, end, key) < 0)            bottom = mid + 1;        else            top = mid;    }    start = (unsigned char *)vptr->datap + top * vptr->elementSize;    end = (unsigned char *)start + vptr->elementSize;    if (bottom > top || compare_interval_func(start, end, key) != 0) return -1;    return top;}





原创粉丝点击