增加IndexedList模板,但未测试。
This commit is contained in:
parent
33f0ed3258
commit
365075ba88
@ -49,6 +49,14 @@ namespace hgl
|
|||||||
return count-vil.count;
|
return count-vil.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetData(T *data,int64 data_count)
|
||||||
|
{
|
||||||
|
Free();
|
||||||
|
|
||||||
|
items=data;
|
||||||
|
alloc_count=count=data_count;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,6 +182,15 @@ namespace hgl
|
|||||||
return items[n];
|
return items[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Append(const T &obj)
|
||||||
|
{
|
||||||
|
if(count>=alloc_count)
|
||||||
|
Alloc(count+1);
|
||||||
|
|
||||||
|
items[count]=obj;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
T *At(int64 n)const
|
T *At(int64 n)const
|
||||||
{
|
{
|
||||||
return (n<0||n>=count)?nullptr:items+n;
|
return (n<0||n>=count)?nullptr:items+n;
|
||||||
|
409
inc/hgl/type/IndexedList.h
Normal file
409
inc/hgl/type/IndexedList.h
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include<hgl/type/Stack.h>
|
||||||
|
#include<initializer_list>
|
||||||
|
|
||||||
|
namespace hgl
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 索引数据列表<br>
|
||||||
|
* IndexedList与ArrayList功能类似,但它的区别是它使用索引来访问数据。
|
||||||
|
* 当数据被移动、删除、排序时,数据本身的内存并不会变动,只会调整索引。
|
||||||
|
*/
|
||||||
|
template<typename T,typename I=int32> class IndexedList
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
DataArray<T> data_array;
|
||||||
|
DataArray<I> data_index;
|
||||||
|
Stack<I> free_index;
|
||||||
|
|
||||||
|
public: //属性
|
||||||
|
|
||||||
|
const int32 GetAllocCount ()const{return data_array.GetAllocCount();}
|
||||||
|
const int32 GetCount ()const{return data_index.GetCount();}
|
||||||
|
const int32 GetFreeCount ()const{return free_index.GetCount();}
|
||||||
|
|
||||||
|
const size_t GetTotalBytes ()const{return data_index.GetCount()*sizeof(T);}
|
||||||
|
|
||||||
|
const bool IsEmpty ()const{return data_index.IsEmpty();}
|
||||||
|
|
||||||
|
bool PreAlloc(int32 count)
|
||||||
|
{
|
||||||
|
if(count<=0)return(false);
|
||||||
|
|
||||||
|
data_array.Alloc(count);
|
||||||
|
data_index.Alloc(count);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // 迭代器
|
||||||
|
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
IndexedList<T,I> *list;
|
||||||
|
int32 current_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using value_type = T;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Iterator(const IndexedList<T, I>* lst, int32 idx):list(lst),current_index(idx){}
|
||||||
|
|
||||||
|
T& operator*() const
|
||||||
|
{
|
||||||
|
return list->data_array[list->data_index[current_index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator &operator++(){current_index++;return *this;}
|
||||||
|
Iterator operator++(int){Iterator tmp=*this;++(*this);return tmp;}
|
||||||
|
|
||||||
|
Iterator &operator--(){current_index--;return *this;}
|
||||||
|
Iterator operator--(int){Iterator tmp=*this;--(*this);return tmp;}
|
||||||
|
|
||||||
|
bool operator==(const Iterator &other) const
|
||||||
|
{
|
||||||
|
return current_index==other.current_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Iterator &other) const
|
||||||
|
{
|
||||||
|
return current_index!=other.current_index;
|
||||||
|
}
|
||||||
|
};//class Iterator
|
||||||
|
|
||||||
|
Iterator begin() const
|
||||||
|
{
|
||||||
|
return Iterator(this,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator end() const
|
||||||
|
{
|
||||||
|
return Iterator(this,data_index.GetCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator last() const
|
||||||
|
{
|
||||||
|
return Iterator(this,data_index.GetCount()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
IndexedList()=default;
|
||||||
|
IndexedList(const T *lt,const int n){Add(lt,n);}
|
||||||
|
IndexedList(const IndexedList<T,I> <){operator=(lt);}
|
||||||
|
IndexedList(const std::initializer_list<T> <){operator=(lt);}
|
||||||
|
virtual ~IndexedList(){Free();}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向列表中添加一个空数据
|
||||||
|
* @return 这个数据的指针
|
||||||
|
*/
|
||||||
|
virtual T *Add()
|
||||||
|
{
|
||||||
|
if(free_index.IsEmpty())
|
||||||
|
{
|
||||||
|
data_array.AddCount(1);
|
||||||
|
return data_array.last();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int32 index;
|
||||||
|
|
||||||
|
free_index.Pop(index);
|
||||||
|
data_index.Append(index);
|
||||||
|
|
||||||
|
return data_array.At(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向列表中添加一个数据对象
|
||||||
|
* @param data 要添加的数据对象
|
||||||
|
* @return 这个数据的索引号
|
||||||
|
*/
|
||||||
|
virtual int32 Add(const T &data)
|
||||||
|
{
|
||||||
|
int32 index;
|
||||||
|
|
||||||
|
if(free_index.IsEmpty())
|
||||||
|
{
|
||||||
|
index=data_array.GetCount();
|
||||||
|
|
||||||
|
data_array.AddCount(1);
|
||||||
|
data_index.Append(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free_index.Pop(index);
|
||||||
|
data_index.Append(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
hgl_cpy<T>(data_array[index],data);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向列表中添加一批数据对象
|
||||||
|
* @param data 要添加的数据对象
|
||||||
|
* @param n 要添加的数据数量
|
||||||
|
* @return 添加了几个
|
||||||
|
*/
|
||||||
|
virtual int32 Add(const T *data,int n)
|
||||||
|
{
|
||||||
|
if(!data||n<=0)
|
||||||
|
return(-1);
|
||||||
|
|
||||||
|
const int32 fc=free_index.GetCount();
|
||||||
|
|
||||||
|
int32 result=0;
|
||||||
|
|
||||||
|
if(fc>0) //如果有剩余的空间
|
||||||
|
{
|
||||||
|
const int32 mc=hgl_min(fc,n);
|
||||||
|
|
||||||
|
int32 index=data_array.GetCount();
|
||||||
|
|
||||||
|
data_array.AddCount(n);
|
||||||
|
data_index.AddCount(n);
|
||||||
|
|
||||||
|
for(int32 i=0;i<mc;i++)
|
||||||
|
{
|
||||||
|
free_index.Pop(index);
|
||||||
|
data_index.Append(index);
|
||||||
|
|
||||||
|
hgl_cpy<T>(data_array[index],data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
n-=mc;
|
||||||
|
data+=mc;
|
||||||
|
|
||||||
|
result=mc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//剩余空间没了
|
||||||
|
|
||||||
|
if(n>0) //如果还有,那就整段添加吧
|
||||||
|
{
|
||||||
|
int32 index=data_array.GetCount();
|
||||||
|
|
||||||
|
data_array.AddCount(n);
|
||||||
|
data_index.AddCount(n);
|
||||||
|
|
||||||
|
for(int32 i=0;i<n;i++)
|
||||||
|
data_index[index+i]=index+i;
|
||||||
|
|
||||||
|
hgl_cpy<T>(data_array.At(index),data,n);
|
||||||
|
|
||||||
|
result+=n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Clear()
|
||||||
|
{
|
||||||
|
data_array.Clear();
|
||||||
|
data_index.Clear();
|
||||||
|
free_index.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Free()
|
||||||
|
{
|
||||||
|
data_array.Free();
|
||||||
|
data_index.Free();
|
||||||
|
free_index.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool IsValidIndex(const int32 index)const
|
||||||
|
{
|
||||||
|
return !(index<0||index>=data_index.GetCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据
|
||||||
|
* @param start 起始删除的数据索引
|
||||||
|
* @param count 删除个数
|
||||||
|
* @return 删除成功的数据个数
|
||||||
|
*/
|
||||||
|
virtual int32 DeleteAt(int32 start,int32 count=1)
|
||||||
|
{
|
||||||
|
if(!IsValidIndex(start)return(-1);
|
||||||
|
if(count<=0)return(count);
|
||||||
|
|
||||||
|
if(start+count>data_index.GetCount())
|
||||||
|
count=data_index.GetCount()-start;
|
||||||
|
|
||||||
|
if(count<=0)return(0);
|
||||||
|
|
||||||
|
for(int32 i=start;i<data_index.GetCount();i++)
|
||||||
|
free_index.Push(data_index[i]);
|
||||||
|
|
||||||
|
data_index.Delete(start,count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Exchange(int32 a,int32 b)
|
||||||
|
{
|
||||||
|
if(!IsValidIndex(a))return(false);
|
||||||
|
if(!IsValidIndex(b))return(false);
|
||||||
|
|
||||||
|
hgl_swap(data_index[a],data_index[b]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收缩数据
|
||||||
|
* 将所有数据收缩到前面
|
||||||
|
*/
|
||||||
|
virtual bool Shrink()
|
||||||
|
{
|
||||||
|
if(data_index.IsEmpty())
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
const int32 count=GetCount();
|
||||||
|
|
||||||
|
DataArray<int32> sorted_index(count);
|
||||||
|
Stack<int32> overflow_index;
|
||||||
|
Stack<int32> space_location;
|
||||||
|
|
||||||
|
overflow_index.PreAlloc(count);
|
||||||
|
space_location.PreAlloc(count);
|
||||||
|
|
||||||
|
hgl_cpy(sorted_index.GetData(),data_index.GetData(),count);
|
||||||
|
|
||||||
|
std::sort(sorted_index.GetData(),count,sizeof(int32),[](const void *a,const void *b)
|
||||||
|
{
|
||||||
|
return *(int32 *) a-*(int32 *) b;
|
||||||
|
});
|
||||||
|
|
||||||
|
//查找空的位置
|
||||||
|
{
|
||||||
|
int32 *p=sorted_index.GetData();
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++)
|
||||||
|
{
|
||||||
|
if(i<*p)
|
||||||
|
{
|
||||||
|
space_location.Push(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//查找超出边界的索引
|
||||||
|
{
|
||||||
|
int32 *p=data_index.GetData();
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++)
|
||||||
|
{
|
||||||
|
if(*p>=count)
|
||||||
|
{
|
||||||
|
overflow_index.Push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(overflow_index.IsEmpty())
|
||||||
|
return(true);
|
||||||
|
|
||||||
|
if(overflow_index.GetCount()!=space_location.GetCount())
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
//直接将超出边界的数据移到空的位置上,并更新索引
|
||||||
|
{
|
||||||
|
int32 new_location;
|
||||||
|
int32 index;
|
||||||
|
|
||||||
|
while(space_location.Pop(new_location))
|
||||||
|
{
|
||||||
|
overflow_index.Pop(index);
|
||||||
|
|
||||||
|
hgl_cpy<T>(data_array.At(new_location),data_array.At(data_index[index]));
|
||||||
|
|
||||||
|
data_index[index]=new_location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_index.Clear();
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前数据是否顺序排好的
|
||||||
|
*/
|
||||||
|
const bool IsOrdered()const
|
||||||
|
{
|
||||||
|
const int count=data_index.GetCount();
|
||||||
|
const int32 *p=data_index.GetData();
|
||||||
|
|
||||||
|
for(int i=0;i<count;i++)
|
||||||
|
{
|
||||||
|
if(i!=*p)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Reorder()
|
||||||
|
{
|
||||||
|
const int count=data_index.GetCount();
|
||||||
|
|
||||||
|
if(count<=0)return;
|
||||||
|
|
||||||
|
if(IsOrdered()) //顺序没问题
|
||||||
|
return;
|
||||||
|
|
||||||
|
T *temp_array=hgl_align_malloc<T>(count);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
int start = i; // 当前连续块的起始位置
|
||||||
|
int end = i; // 当前连续块的结束位置
|
||||||
|
|
||||||
|
// 检查后续索引是否是连续的正确顺序
|
||||||
|
while (end + 1 < count && data_index[end + 1] == data_index[end] + 1)
|
||||||
|
{
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量复制连续块的数据
|
||||||
|
int length = end - start + 1;
|
||||||
|
hgl_cpy<T>(temp_array+start, data_array.GetData() + data_index[start], length);
|
||||||
|
|
||||||
|
// 更新索引
|
||||||
|
i = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将临时数组的数据复制回 data_array
|
||||||
|
data_array.SetData(temp_array,count);
|
||||||
|
|
||||||
|
// 更新 data_index,使其与 data_array 的顺序一致
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
data_index[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};//template<typename T> class IndexedList
|
||||||
|
}//namespace hgl
|
Loading…
x
Reference in New Issue
Block a user