使用C ++,我试图创建一个数组,该数组包含指向我存储的对象的指针。但是当阵列已满时,我想扩展数组。
简单的选择是分配一个更大的新数组,然后将元素复制到它,这是非常低效的,我想到了另一种我想尝试的方式:
创建固定大小为X的数组
完整后,创建一个新数组,并使第一个数组的结尾指向第一个元素的开头
根据需要重复
我可以使用哪些方法来做到这一点?我想到了一种方法,但它似乎非常hacky:
将我的所有新数组声明为指向对象指针的指针,然后将填充的元素reinterprit_cast转换为对象指针。
注意:我知道我可以使用Vector,但我被告知不使用标准库。
亲切的问候,
答案 0 :(得分:1)
使用C ++,我试图创建一个包含指针的数组 对象我存储。但是当数组已满时,我想扩展数组 阵列。
使用C ++模板和C基元,我们可以即兴创建一个简单的向量。增长缓冲策略是在达到阈值时将尺寸加倍。
#include <iostream>
#include <stdlib.h>
template <typename T>
class MyVector
{
public:
MyVector() : m_count(0), m_size(0), m_buffer(0)
{
m_size = bufInitSize;
m_buffer = (T*)malloc(sizeof(T) * bufInitSize);
}
~MyVector()
{
if (m_buffer)
free(m_buffer);
}
void add(const T& p)
{
if (m_count + 1 >= m_size)
{
m_size *= 2;
m_buffer = (T*)realloc(m_buffer, sizeof(T) * m_size);
}
m_buffer[m_count ++ ] = p;
}
T& operator[](int idx)
{
return m_buffer[idx];
}
private:
static const int bufInitSize = 1024;
T* m_buffer;
int m_count;
int m_size;
};
void main()
{
// using MyVector
MyVector<int*> vctOfIntPtr;
int n = 100;
vctOfIntPtr.add(&n);
int* pN = vctOfIntPtr[0];
std::cout << *pN;
}
答案 1 :(得分:1)
评论中已有一些好的答案。我只想提供一种方法来实现完全您描述的行为。
由于数组的元素也是指针,你可以将union定义为数组的元素,如下所示:
template<typename T>
union Cell
{
T* pElm;
Cell* pNext;//A fixed size array of Cells
}
然后在它上面构建你的数组。例如:
template<typename T>
class SpecialArray
{
public:
//the next pointer is included
static const size_t ARRAY_LEN = 1000;// For example
using Pointer = T*;
using Segment = Cell<T>[ARRAY_LEN];
protected:
Segment* pFirst;
size_t mSize;
public:
SpecialArray()
:pFirst(nullptr),mSize(0){}
SpecialArray(SpecialArray&&){}
~SpecialArray(){}
Pointer& operator[](size_t index)
{
Segment* seg = pFirst;
size_t offest = 0;
//Search logic...
return seg[offest]->pElm;
}
const Pointer& operator[](size_t index) const;
};
答案 2 :(得分:1)
另一个解决方案是存储大型固定大小的用户数据数组,然后您可以快速迭代。一些可能性:
std::vector<T*>data; // Using 1024-element arrays
int nStored = 0;
void push (T elem) {
if (nStored%1024==0) {
data.push_back(new T [1024]);
data.back()[0] = elem;
}
else {
data.back()[(nStored-1)%1024] = elem;
}
nStored++;
}
void pop () {
if (nStored==0) return;
if ((nStored-1)%1024==0) {
delete data.back();
data.pop_back();
}
nStored--;
}
std::list<T*>data;
int nStored = 0;
// Same push() and pop() as for vector<T*>
struct node {
T* data;
int sz;
int last; // Index of last element stored
const bool operator< (const node& o) const {
return last<o.last;
}
}
std::set<node> data;
int nStored = 0;
int capacity = 0;
void push (T elem) {
if (nStored == capacity) {
int nSize = 1024; // This doesn't have to be fixed, you could attach a
// more intelligent algorithm to it to optimise the
// number of times you have to add and remove nodes.
node n; n.sz = nSize; n.data = new T [n.sz]; n.last = nStored+nSize-1;
data.insert(n);
n.data[0] = elem;
capacity += nSize;
}
else {
node n,cNode; n.last = nStored;
cNode = *data.lower_bound(n);
cNode.data[nStored-(cNode.last-cNode.sz+1)] = elem;
}
nStored++;
}
void pop () {
node n,cNode; n.last = nStored-1;
cNode = *data.lower_bound(n);
if ( (cNode.last+1-cNode.sz) == (nStored-1) ) {
delete cNode.data;
data.erase(data.lower_bound(n));
capacity -= cNode.sz;
}
nStored--;
}
T& at (int idx) {
if (idx<0 || idx>=nStored) throw;
node n,cNode; n.last = idx;
cNode = *data.lower_bound(idx);
return cNode.data[idx-(cNode.last+1-cNode.sz)];
}
显然,您无法使用STL容器解决问题,但在C中实现它们非常简单。我只是用它们来说明。
所有这些可能性都基于拥有大型固定大小的用户数据数组的想法,然后能够以某种方式找到合适的数组。
前两个的at()函数相当简单,但我发现使用不同大小的数组的想法,如最后一种可能性所示,很有趣。这个想法的真正强大之处在于,您可以实现一种更有效的算法来分配固定大小的数组,而不仅仅是使它们保持不变的大小。
如果你使用&#39;设置&#39;如上所述,新节点的插入和删除是对数时间而不是摊销常数。但是,查找也是对数的。
使用&#39;向量&#39;会更好,因为插入和删除基本上是不变的,您可以二进制搜索向量以找到正确的节点。
使用&#39;列表&#39;仍会有不断的插入/删除但查找会更慢(因为你只能在列表中线性迭代)。
但出于实际目的,除非您处理绝对庞大的数据集,否则它不会产生巨大的差异