简单数组结构posarr及操作

其实这是一种“假”的数据结构,没有什么新的结构,甚至平行数组都没有,它就是一个简单的……数组

1
typedef int *posarr_p;

一切操作,都围绕着这个如假包换的数组展开。

就是有这种操作

使用数组的第一个元素储存长度容易导致很多不良后果——比如遍历数组时,索引和元素的“位置”的偏差。因此我的解决方案是:没有使用的元素填-1,最后一个元素填-2,并且不使用它——不然就没法确定数组的结尾了。

那么如果数据是-1或者-2怎么办?好办,要求数据不能小于0就行了。

1
2
3
4
5
void posarr_initia(posarr_p memo, const int size) {
for (int i = 0; i < size; i++)
memo[i] = -1;
memo[size] = -2;
}

宏替换函数不推荐作为内联函数使用了,不过用来完成一些语言能力之外的事情还是可以的:

1
#define POSARR(name, size) int name[size + 1]; posarr_initia(name, size)

删除一个元素时用后面的元素填充,而添加元素时只要简单的在末尾找到一个空位就行了。目前的删除动作把每一个元素都向前移了一位,如果不在乎顺序的话可以拿最后一个元素填补空位,可以进一步提高效率:

1
2
3
4
5
6
7
8
9
int posarr_delete(posarr_p array, const int pos) {
if (array[pos] < 0)
return 1;
int i;
for (i = pos; array[i + 1] >= 0; i++)
array[i] = array[i + 1];
array[i] = -1;
return 0;
}
1
2
3
4
5
6
7
8
9
int posarr_append(posarr_p array, const int data) {
assert(data >= 0);
for (int i = 0; array[i] != -2; i++)
if (array[i] == -1) {
array[i] = data;
return 0;
}
return 1;
}

还有一个喜闻乐见的toString工具函数。由于数据结构的限制,没有找到在一趟之内且不借助buffer的方法来先输出长度再输出各元素,所以只好遍历两趟。好在对于这种小数组,对于它的使用场景一般不会超过16个元素的长度,所以效率上不会有显著瓶颈。代码不贴了,效果大概是这样:

1
posarr#10[0, 1, 2, 3, 4, 5, 6, 7, ...]

只显示前八个元素,这样就算放在一行log当中也不会太尴尬。

最后,一个用来遍历数组的工具宏替换函数:

1
2
3
#define POSARR_ITERAT(array, item, index) \
for (int index = 0, item = array[index]; item >= 0; \
index++, item = array[index])

就是这些。下一步会添加刚刚想到的删除函数,并且把这个数据结构用来作邻接表组成的图数据结构的基石。