当我们需要一个动态数组来存数据时,都是使用的T * p = (T *)malloc(sizeof(T) * n);
众所周知,这个方法有严重的使用问题:
1) p指向的内存,其大小信息丢失了。
2) 数组没有赋初值
3) 数组没有办法自动扩大内存,所以越界问题一直令人头痛
4) 对数组的常用算法,都没有提供可重用的代码
所以,需要你们对动态数组进行封装
用
typedef struct
{
T * pStart;
//其它任何你认为需要额外增加的字段
} VECTOR;
提供如下形式的算法函数
1) VECTOR Create(void); 创建一个空数组,里面元素个数为0
VECTOR Create_n(int n);创建一个空数组,里面元素个数为n,每个元素都调用Init_T函数进行了赋初值。
VECTOR Create_n(int n, T t);创建一个空数组,里面元素个数为n,每个元素都赋初值为t。
void Destory(VECTOR *);销毁掉数组,回收内存
2) int Size(VECTOR *);获得VECTOR里的元素个数
3) T * Front(VECTOR *);获得VECTOR里的第一个元素的指针。请说明元素个数为0时,你的函数返回什么结果
T * Back(VECTOR *);获得VECTOR里的最后一个元素的指针。请说明元素个数为0时,你的函数返回什么结果
4) T * Begin(VECTOR *); T * End(VECTOR *);返回的2个指针构成半闭半开区间[begin, end)指示出数组里所有元素。
所谓半闭半开区间就是包括begin所指元素,但不包括end所指元素。半闭半开区间是数据使用上一个极重要的概念,因为它能表示空集合。配合下面的Next,你就可以在不管是否有元素的情况下都可简单地进行遍历了。
for (T * p = Begin(&v); p != End(&v); Next(&v, p))
{
//Do Something Here!
}
T * Next(VECTOR *, T *);假定传入的指针确保指向vector里的某个元素,给出它的下一个元素的指针。请说明已经指向最后一个元素时,你的函数返回什么结果。
T * Prev(VECTOR *, T *);假定传入的指针确保指向vector里的某个元素,给出它的前一个元素的指针。请说明已经指向第一个元素时,你的函数返回什么结果。
5) T * Find(VECTOR *, T t);搜索第一个值为t的元素,返回其指针。请说明没找到时,你的函数返回什么结果。
int Count(VECTOR *, T t);计算值为t的元素的个数
6) T * Insert(VECTOR *, T * pos, T t);将pos所指元素及后面所有元素后移,将t插入到指针pos所指位置。返回新插入的元素的指针。如果插入元素将导致总元素个数超过原先分配的内存,必须重新分配内存进行扩容
T * InsertRange(VECTOR *, T * pos, T * first, T * last);将[first, last)所指区间中所有元素保持原顺序插入到pos所指元素之前。返回新插入的第一个元素的指针。如果插入元素将导致总元素个数超过原先分配的内存,必须重新分配内存进行扩容
void Push_Back(VECTOR, T t);在数组最后追加一个元素。
T * Erase(VECTOR *, T * pos);删除指针pos所指元素,将后面的元素进行前移。返回被删除的元素的下一个元素的现在的指针。
T * EraseRange(VECTOR *, T * first, T * last);删除指针[first, last)所指区间中的元素,将后面的元素进行前移。返回最后一个删除的元素的下一个元素的现在的指针。
void Pop_Back(VECTOR *, T t);删除数组的最后一个元素。
void Clear(VECTOR *);清空所有元素。
BOOL Remove(VECTOR *, T t);删除所有值为t的元素,剩下的元素进行前移以保持连续。返回“是否进行了删除”。
7) void Assign(VECTOR * l, const VECTOR * r);使得l所指内存拥有和r完全相同的元素,而不是l.p和r.p指向相同的地址。如果2者元素个不匹配,也许要重新分配内存分配。
void Swap(VECTOR * l, const VECTOR * r);使得l拥有原来r的元素,r拥有l原来的元素。
VECTOR Create_byVector(const VECTOR * v)//创建和v具有完全相同元素的新VECTOR
VECTOR Create_byArray(const T * first, const T * last)//创建和[first, last)所指数组区间相同的元素的新VECTOR
8) 附加题:
BOOL Empty(const VECTOR * v)//如果没有元素,返回TRUE,其它情况返回FLASE
void Resize(VECTOR * v, int n)//如果n < Size(v),删除尾部Size(v) - n个元素,如果n > Size(v),在尾部追加n - Size(v)个Init_T函数来初始化的新元素。
void Resize_with_t(VECTOR * v, int n, T t)//如果n < Size(v),删除尾部Size(v) - n个元素,如果n > Size(v),在尾部追加n - Size(v)个值等于t的元素。
T * At(VECTOR *, int n),返回数组里下标为n的元素的指针
void Assign_byArray(VECTOR * v, const T * first, const T * last)//使得v现在含有和[first, last)所指数组区间相同的元素
BOOL Equal(const VECTOR * l, const VECTOR * r)//当2个VECTOR元素个数并且按顺序,每个元素都相同时,返回TRUE
BOOL Less(const VECTOR * l, const VECTOR * r)//按字典序进行比较,l < r时返回TRUE。字典序就是 a开始的所有单词 < b开头的所有单词;a在所有a开头的单词里最小;其它a开头的单词根据第二个字母起继续比较。
9) 提高题:
实现Find、Count、Remove操作的扩展。
要能完成比如“Count(Vector *, XXXXXX);能计算所有值大于x的元素的个数”这样的通用问题。
10) 再提高题:
VECTOR用create函数创建后,因为分配了内存,所以必须用destory销毁的。而且每create一次,就得有且仅有一次对应的destory。
如果有如下代码VECTOR v1 = CREATE_n(2);
VECTOR v2 = CREATE_n(3);
v2 = v1;
那么将导致v2在create过程中分配的内存就泄漏了。
所以,问题是:如何能防止不小心的v2 = v1这类行为?
在你们的VECTOR代码里想办法完成,而不是指望使用VECTOR的人总不犯错。