假设我有三个阵列:
const uint8_t arr_1[] = {1, 4, 53 , 209};
const uint8_t arr_2[] = {54, 56, 90, 100};
const uint8_t arr_3[] = {6, 7, 8, 9, 10};
如何有效地检查给定值uint8_t val
是否在其中一个数组中,如果是,则在哪一个数组中。一种方法是循环遍历所有数组,直到找到该值,但这不是非常有效。该解决方案需要扩展到更多阵列。如有必要,可以对每个数组中的值进行排序。
答案 0 :(得分:3)
我将在答案中总结我对您帖子的评论。希望它对某人有用。
如果你为每个数组保持一个指针及其值范围,比如说:
struct arr_meta_data {
const uint8_t *p_arr;
uint8_t min;
uint8_t max;
};
然后,您可以根据范围定义的部分顺序对struct arr_meta_data
数组进行排序。
查找值是一个两步过程
在struct arr_meta_data
数组中进行二进制搜索,以查找值可以所在的第一个数组。 O(log M)
其中M
是您拥有的阵列数。
在值在范围内的每个数组中前进和二进制搜索。到达数值小于最小值的数组后,您可以停止并返回找不到该值的数据。
答案 1 :(得分:2)
受到@StoryTeller的启发,我尝试使用他的方法。
我只考虑给出的3个数组构建了代码:
const uint8_t arr_1[] = {1, 4, 53 , 209};
const uint8_t arr_2[] = {54, 56, 90, 100};
const uint8_t arr_3[] = {6, 7, 8, 9, 10};
因为我不知道如何给出数据。这个想法是正确的,我假设数组总是排序。如果将来不是这种情况,那么您可以事先使用qsort
对数组进行排序,平均运行时间 O(nlogn)。
在下面的代码中,我使用了:
stdlib.h
提供的内置bsearch
功能,以省去编写自己的功能。使用此二进制搜索工具仍然允许 O(logn)搜索时间,这比线性搜索消耗的 O(n)时间要好得多。 结构设置数组,用于收集有关每个数组的特定信息,例如检查[min, max]
范围,以及跳过与搜索键值不在同一范围内的数组
设定:
typedef struct {
const uint8_t *p_arr;
uint8_t currsize; * size of each array */
uint8_t max; /* Ranges */
uint8_t min;
} array_t;
typedef struct {
array_t *A; /* pointer to array information */
uint8_t numarrays; /* just a buddy vairable to keep track of n arrays */
} data_t;
malloc
和free
的必要调用,为堆上的指针变量分配和释放空间。 以下是我提出的建议:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define INITSIZE 3
typedef struct {
const uint8_t *p_arr;
uint8_t currsize;
uint8_t max;
uint8_t min;
} array_t;
typedef struct {
array_t *A;
uint8_t numarrays;
} data_t;
data_t *initialize_meta_data(void);
int check_arrays(const uint8_t arr[], const size_t n, uint8_t *key);
void set_arrays(data_t *data, const uint8_t arr[], const size_t n, int index);
void search_arrays(data_t *data, uint8_t key);
int cmpfunc(const void *a, const void *b);
int
main(void) {
const uint8_t arr_1[] = {1, 4, 53 , 209};
const uint8_t arr_2[] = {54, 56, 90, 100};
const uint8_t arr_3[] = {6, 7, 8, 9, 10};
const size_t size1 = sizeof(arr_1)/sizeof(*arr_1);
const size_t size2 = sizeof(arr_2)/sizeof(*arr_2);
const size_t size3 = sizeof(arr_3)/sizeof(*arr_3);
data_t *data = initialize_meta_data();
data->A = malloc(data->numarrays * sizeof(*(data->A)));
set_arrays(data, arr_1, size1, 0);
set_arrays(data, arr_2, size2, 1);
set_arrays(data, arr_3, size3, 2);
/* Number to search for */
uint8_t key = 10;
search_arrays(data, key);
free(data->A);
free(data);
return 0;
}
void
search_arrays(data_t *data, uint8_t key) {
int i;
for (i = 0; i < data->numarrays; i++) {
if ((key <= data->A[i].max) && (key >= data->A[i].min)) {
if (check_arrays(data->A[i].p_arr, data->A[i].currsize, &key)) {
printf("%d found in array number: %d\n", key, i+1);
}
} else {
printf("array number: %d skipped\n", i+1);
}
}
}
void
set_arrays(data_t *data, const uint8_t arr[], const size_t n, int index) {
data->A[index].p_arr = arr;
data->A[index].currsize = n;
data->A[index].max = data->A[index].p_arr[data->A[index].currsize-1];
data->A[index].min = data->A[index].p_arr[0];
}
data_t
*initialize_meta_data(void) {
data_t *data = malloc(sizeof(*data));
data->A = NULL;
data->numarrays = INITSIZE;
return data;
}
int
check_arrays(const uint8_t arr[], const size_t n, uint8_t *key) {
uint8_t *item;
item = bsearch(key, arr, n, sizeof(*arr), cmpfunc);
if (item != NULL) {
return 1;
}
return 0;
}
int
cmpfunc(const void *a, const void *b) {
return (*(uint8_t*)a > *(uint8_t*)b) - (*(uint8_t*)a < *(uint8_t*)b);
}
总的来说,这个代码可以进行大量优化,你可能会对你的项目使用一种非常不同的方法,但这个想法是类似的。
我希望它有所帮助:)。
答案 2 :(得分:0)
#include <stdio.h>
#include <stdint.h>
const uint8_t arr_1[] = {1, 4, 53 , 209};
const uint8_t arr_2[] = {54, 56, 90, 100};
const uint8_t arr_3[] = {6, 7, 8, 9, 10};
uint8_t lookup[256] = {0,};
void add_one(const uint8_t *arr, unsigned count, unsigned num)
{
unsigned uu, val;
for (uu=0; uu < count; uu++) {
val = arr[uu];
if (lookup[val]) fprintf(stderr
, "Add_one(num = %u): OMG!1111! value=%u also present in array_%u\n"
, num, val, (unsigned) lookup[val] );
lookup[val] = num;
}
}
void do_init(void)
{
add_one(arr_1, 4, 1);
add_one(arr_2, 4, 2);
add_one(arr_3, 6, 3);
}
int main(void)
{
unsigned idx,val;
do_init();
for (val = 0; val < 256; val++) {
idx = lookup[val];
if (!idx) continue;
printf("Value %u is in arr_%u\n", val, idx);
}
return 0;
}
答案 3 :(得分:0)
因为它是uint8_t你可以使用一个bitarray。没有排序没有循环。 此代码未经过测试,但可以看到这个想法。
uint arrEle(uint8_t val) { return val/32; }
uint arrBit(uint8_t val) { return 1<<(val%32); }
void setBit(uint32_t *arr, uint8_t val) {
arr[arrEle(val)]|=arrBit(val);
}
uint testBit(uint32_t *arr, uint8_t val) {
return (arr[arrEle(val)]&arrBit(val)) ? 1:0;
}
void clrBit(uint32_t *arr, uint8_t val) {
arr[arrEle(val)]&=~arrBit(val);
}
// sorry not static initialize
const uint32_t arr_all[4][8] = {0};
const uint32_t arr_1[][8] = arr_all[0];
const uint32_t arr_2[][8] = arr_all[1];
setBit(arr_1, 1);
setBit(arr_1, 4);
setBit(arr_1, 53);
setBit(arr_1, 209);
现在您的测试非常简单:
for(i=0;i<sizeof(arr_all)/sizeof(*arr_all);i++)
if(testBit(arr_all[i], val)) return i; // return the array number 0..3