其实这是一种“假”的数据结构,没有什么新的结构,甚至平行数组都没有,它就是一个简单的……数组
一切操作,都围绕着这个如假包换的数组展开。
使用数组的第一个元素储存长度容易导致很多不良后果——比如遍历数组时,索引和元素的“位置”的偏差。因此我的解决方案是:没有使用的元素填-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])
|
就是这些。下一步会添加刚刚想到的删除函数,并且把这个数据结构用来作邻接表组成的图数据结构的基石。