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

要点:

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 __cplusplus
extern "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;
}






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值