简介
我对你的问题做了一个强有力的假设,它是 sparsness(你的数组中的大部分元素将保持为零)。
在这种假设下,我会将数组构建为 list。我包含了一个示例代码,它不完整,也不打算
是---你应该做你自己的功课:)
核心对象是一个结构体,其指针指向begin 元素和大小:
typedef struct vector {
size_t size;
vector_element_t * begin;
} vector_t;
向量的每个元素都有自己的索引和值以及指向列表中下一个元素的指针:
typedef struct vector_element vector_element_t;
struct vector_element {
int value;
size_t index;
vector_element_t *next;
};
在此基础上,我们可以将动态向量构建为列表,通过删除排序约束(不需要,您可以修改此代码
保持顺序),使用一些简单的自定义方法:
vector_t * vector_init(); // Initialize an empty array
void vector_destroy(vector_t* v); // Destroy the content and the array itself
int vector_get(vector_t *v, size_t index); // Get an element from the array, by searching the index
size_t vector_set(vector_t *v, size_t index, int value); // Set an element at the index
void vector_delete(vector_t *v, size_t index); // Delete an element from the vector
void vector_each(vector_t *v, int(*f)(size_t index, int value)); // Executes a callback for each element of the list
// This last function may be the response to your question
Test it online
主要例子
这是一个使用所有这些方法并在控制台中打印的 main:
int callback(size_t index, int value) {
printf("Vector[%lu] = %d\n", index, value);
return value;
}
int main() {
vector_t * vec = vector_init();
vector_set(vec, 10, 5);
vector_set(vec, 23, 9);
vector_set(vec, 1000, 3);
printf("vector_get(vec, %d) = %d\n", 1000, vector_get(vec, 1000)); // This should print 3
printf("vector_get(vec, %d) = %d\n", 1, vector_get(vec, 1)); // this should print 0
printf("size(vec) = %lu\n", vec->size); // this should print 3 (the size of initialized elements)
vector_each(vec, callback); // Calling the callback on each element of the
// array that is initialized, as you asked.
vector_delete(vec, 23);
printf("size(vec) = %lu\n", vec->size);
vector_each(vec, callback); // Calling the callback on each element of the array
vector_destroy(vec);
return 0;
}
还有输出:
vector_get(vec, 1000) = 3
vector_get(vec, 1) = 0
size(vec) = 3
Vector[10] = 5
Vector[23] = 9
Vector[1000] = 3
size(vec) = 3
Vector[10] = 5
Vector[1000] = 3
带有vector_each 函数的callback 是你真正应该看看的东西。
实现
我将在介绍中为您提供一些简单的功能实现。它们并不完整,
并且应该引入对指针的一些检查。我把它留给你。事实上,此代码不适用于生产,在某些情况下也可能溢出。
特定部分是向量中特定元素的搜索。每次遍历列表时,
这只有在你有稀疏性的情况下才方便(你的大部分索引总是返回零)。
在此实现中,如果您访问未登记的索引,则结果为 0。如果您不想要这个
你应该定义一个错误回调。
初始化和销毁
初始化时,我们为向量分配内存,但里面没有元素,因此begin 指向NULL。当我们销毁向量时,我们不仅要释放向量,还要释放所包含的每个元素。
vector_t * vector_init() {
vector_t * v = (vector_t*)malloc(sizeof(vector_t));
if (v) {
v->begin = NULL;
v->size = 0;
return v;
}
return NULL;
}
void vector_destroy(vector_t *v) {
if (v) {
vector_element_t * curr = v->begin;
if (curr) {
vector_element_t * next = curr->next;
while (next) {
curr = curr->next;
next = next->next;
if (curr)
free(curr);
}
if (next)
free(next);
}
free(v);
}
}
get 和 set 方法
在 get 你可以看到列表是如何工作的(和相同的概念
也用于设置和删除):我们从头开始,并且
我们遍历列表,直到我们到达一个索引等于的元素
给请求的人。如果我们找不到它,我们只需返回 0。
如果我们需要在值为
没找到,很容易实现“错误回调”。
只要 sparsness 成立,在整个数组中搜索索引就内存需求而言是一个很好的折衷方案,效率可能不是问题。
int vector_get(vector_t *v, size_t index) {
vector_element_t * el = v->begin;
while (el != NULL) {
if (el->index == index)
return el->value;
el = el->next;
}
return 0;
}
// Gosh, this set function is really a mess... I hope you can understand it...
// -.-'
size_t vector_set(vector_t *v, size_t index, int value) {
vector_element_t * el = v->begin;
// Case 1: Initialize the first element of the array
if (el == NULL) {
el = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el != NULL) {
v->begin = el;
v->size += 1;
el->index = index;
el->value = value;
el->next = NULL;
return v->size;
} else {
return 0;
}
}
// Case 2: Search for the element in the array
while (el != NULL) {
if (el->index == index) {
el->value = value;
return v->size;
}
// Case 3: if there is no element with that index creates a new element
if (el->next == NULL) {
el->next = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el->next != NULL) {
v->size += 1;
el->next->index = index;
el->next->value = value;
el->next->next = NULL;
return v->size;
}
return 0;
}
el = el->next;
}
}
删除元素
使用这种方法可以很容易地删除一个元素,连接
curr->next 到 curr->next->next。我们必须释放之前的curr->next...
void vector_delete(vector_t * v, size_t index) {
vector_element_t *curr = v->begin;
vector_element_t *next = curr->next;
while (next != NULL) {
if (next->index == index) {
curr->next = next->next;
free(next);
return;
} else {
curr = next;
next = next->next;
}
}
}
一个迭代函数
我认为这是您问题最后一部分的答案,
而是传递一系列索引,而是将回调传递给向量。
回调获取并设置特定索引中的值。如果你想
仅对某些特定索引进行操作,您可以在
回调本身。如果您需要将更多数据传递给回调,请检查
最后一节。
void vector_each(vector_t * v, int (*f)(size_t index, int value)) {
vector_element_t *el = v->begin;
while (el) {
el->value = f(el->index, el->value);
el = el->next;
}
}
错误回调
您可能想要提出一些越界错误或其他错误。一种解决方案是使用函数指针丰富您的列表,该函数指针表示当您的用户 sk 获取未定义元素时应调用的回调:
typedef struct vector {
size_t size;
vector_element_t *begin;
void (*error_undefined)(vector *v, size_t index);
} vector_t
也许在你的 vector_get 函数结束时,你可能想做一些类似的事情:
int vector_get(vector_t *v, size_t index) {
// [ . . .]
// you know at index the element is undefined:
if (v->error_undefined)
v->error_undefined(v, index);
else {
// Do something to clean up the user mess... or simply
return 0;
}
}
通常最好添加一个辅助函数来设置回调...
将用户数据传递给“每个”回调
如果您想向用户回调传递更多数据,您可以添加void* 作为最后一个参数:
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data));
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data)) {
[...]
el->value = f(el->index, el->value, user_data);
[...]
}
如果用户不需要,可以传一个精彩的NULL。