gctl/lib/core/sparray.h

659 lines
18 KiB
C
Raw Permalink Normal View History

2024-09-10 15:45:07 +08:00
/********************************************************
*
*
*
*
*
*
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#ifndef _GCTL_SPARRAY_H
#define _GCTL_SPARRAY_H
// library's head files
#include "array.h"
#include "enum.h"
namespace gctl
{
template <typename NodeValueType>
struct arr_node
{
int id;
NodeValueType val;
arr_node(){};
arr_node(int in_id, NodeValueType in_val)
{
id = in_id;
val = in_val;
}
};
template <typename ArrayValueType>
class sparray
{
protected:
std::vector<arr_node<ArrayValueType> > arr1d; ///< 稀疏数组存储向量
int full_length; ///< 稀疏数组的全长
ArrayValueType zero_val; ///< 稀疏数组的零值
public:
sparray(); ///< 默认构造函数
sparray(int in_len, ArrayValueType null_val); ///< 构造函数:预留数组空间并制定零值
sparray(const array<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set); ///< 构造函数:从数组初始化
sparray(const std::vector<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set); ///< 构造函数:从向量初始化
sparray(const sparray<ArrayValueType> &b); ///< 拷贝构造函数
sparray<ArrayValueType> &operator= (const sparray<ArrayValueType> &b); ///< 重载赋值操作符
~sparray(); ///< 析构函数
void malloc(int in_len, ArrayValueType null_val); ///< 预留数组空间并制定零值
void malloc(const sparray<ArrayValueType> &b); ///< 从稀疏数组初始化
void malloc(const array<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set); ///< 从数组初始化
void malloc(const std::vector<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set); ///< 从向量初始化
void clear(); ///< 清空数组内容
ArrayValueType value(unsigned int in_id) const; ///< 返回索引值位置的元素值
arr_node<ArrayValueType> at(unsigned int in_id) const; ///< 返回非零元素在索引位置的值
void set(int in_id, ArrayValueType in_val); ///< 在队中添加元素
void remove(int in_id); ///< 删除索引值位置的元素
bool empty() const; ///< 数组是否为空
int size() const; ///< 返回非零元素的个数
int capcity() const; ///< 返回数组的预定长度
ArrayValueType zero_value() const; ///< 返回0值
void show_list(int st_id = 0, int ed_id = 0) const; ///< 显示存储的元素
void show_full() const; ///< 显示完整的数组
void export_dense(array<ArrayValueType> &b, double multipler = 1.0, value_operator_e type = ReplaceVal) const; ///< 输出为全长度的数组
void copy_to(sparray<ArrayValueType> &b, double multipler = 1.0) const; ///< 拷贝到新的稀疏数组
private:
typename std::vector<arr_node<ArrayValueType> >::iterator find_iterator(int in_id);
typename std::vector<arr_node<ArrayValueType> >::const_iterator find_const_iterator(int in_id) const; ///< 寻找索引值位置的元素并返回其迭代器值
typename std::vector<arr_node<ArrayValueType> >::iterator find_gap(int in_id); ///< 寻找包含索引值的左右两个元素并返回右侧元素的迭代器
};
template <typename ArrayValueType>
sparray<ArrayValueType>::sparray()
{
full_length = -1;
}
template <typename ArrayValueType>
sparray<ArrayValueType>::sparray(int in_len, ArrayValueType null_val)
{
full_length = -1;
malloc(in_len, null_val);
}
template <typename ArrayValueType>
sparray<ArrayValueType>::sparray(const array<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set)
{
full_length = -1;
malloc(b, null_val, off_set);
}
template <typename ArrayValueType>
sparray<ArrayValueType>::sparray(const std::vector<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set)
{
full_length = -1;
malloc(b, null_val, off_set);
}
template <typename ArrayValueType>
sparray<ArrayValueType>::sparray(const sparray<ArrayValueType> &b)
{
full_length = -1;
malloc(b);
}
template <typename ArrayValueType>
sparray<ArrayValueType> &sparray<ArrayValueType>::operator= (const sparray<ArrayValueType> &b)
{
if (!empty()) clear();
zero_val = b.zero_value();
full_length = b.capcity();
arr1d.resize(b.size());
for (int i = 0; i < b.size(); i++)
{
arr1d[i] = b.at(i);
}
return this;
}
template <typename ArrayValueType>
sparray<ArrayValueType>::~sparray()
{
clear();
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::malloc(int in_len, ArrayValueType null_val)
{
if (in_len <= 0)
{
std::string err_str = "Invalid array size. From void sparray<T>::malloc(...)";
throw runtime_error(err_str);
}
full_length = in_len;
zero_val = null_val;
arr1d.reserve(in_len);
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::malloc(const sparray<ArrayValueType> &b)
{
if (b.empty())
{
std::string err_str = "The input array is empty. From void sparray<T>::malloc(...)";
throw runtime_error(err_str);
}
else
{
zero_val = b.zero_value();
full_length = b.capcity();
arr1d.resize(b.size());
for (int i = 0; i < b.size(); i++)
{
arr1d[i] = b.at(i);
}
}
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::malloc(const array<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set)
{
if (b.empty())
{
std::string err_str = "The input array is empty. From void sparray<T>::malloc(...)";
throw runtime_error(err_str);
}
else
{
full_length = b.size();
zero_val = null_val;
arr1d.reserve(full_length);
for (int i = 0; i < b.size(); i++)
{
if (b[i] >= zero_val + off_set || b[i] <= zero_val - off_set)
{
set(i, b[i]);
}
}
}
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::malloc(const std::vector<ArrayValueType> &b, ArrayValueType null_val,
ArrayValueType off_set)
{
if (b.empty())
{
std::string err_str = "The input array is empty. From void sparray<T>::malloc(...)";
throw runtime_error(err_str);
}
full_length = b.size();
zero_val = null_val;
arr1d.reserve(full_length);
for (int i = 0; i < b.size(); i++)
{
if (b.at(i) >= zero_val + off_set ||
b.at(i) <= zero_val - off_set)
insert(i, b.at(i));
}
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::clear()
{
//full_length = 0; // 注意清理稀疏数组时不清理此参数,否则需要重新声明此数组
arr1d.clear();
std::vector<arr_node<ArrayValueType> >().swap(arr1d);
return;
}
template <typename ArrayValueType>
ArrayValueType sparray<ArrayValueType>::value(unsigned int in_id) const
{
typename std::vector<arr_node<ArrayValueType> >::const_iterator iter = find_const_iterator(in_id);
if (iter != arr1d.end())
return iter->val;
return zero_val;
}
template <typename ArrayValueType>
arr_node<ArrayValueType> sparray<ArrayValueType>::at(unsigned int in_id) const
{
return arr1d[in_id];
}
/**
* @brief
*
* @param[in] in_id
* @param[in] in_val
*/
template <typename ArrayValueType>
void sparray<ArrayValueType>::set(int in_id, ArrayValueType in_val)
{
if (in_id < 0 || in_id >= full_length)
{
std::string err_str = "The index is out of range. From void sparray<T>::set(...)";
throw runtime_error(err_str);
}
if (in_val == zero_val)
return;
if (arr1d.empty())
{
arr1d.push_back(arr_node<ArrayValueType>(in_id, in_val));
}
else if (in_id > arr1d.back().id) // 输入索引大于向量内的最大索引值
{
arr1d.push_back(arr_node<ArrayValueType>(in_id, in_val));
}
else if (in_id == arr1d.back().id)
{
arr1d.back().val = in_val;
}
else if (in_id < arr1d.front().id)
{
arr1d.insert(arr1d.begin(), arr_node<ArrayValueType>(in_id, in_val));
}
else if (in_id == arr1d.front().id)
{
arr1d.front().val = in_val;
}
// 在中间插入元素比较耗时
else
{
typename std::vector<arr_node<ArrayValueType> >::iterator iter = find_iterator(in_id);
if (iter != arr1d.end()) iter->val = in_val;
else
{
iter = find_gap(in_id);
arr1d.insert(iter, arr_node<ArrayValueType>(in_id, in_val));
}
}
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::remove(int in_id)
{
typename std::vector<arr_node<ArrayValueType> >::iterator iter = find_iterator(in_id);
if (iter != arr1d.end())
arr1d.erase(iter);
return;
}
template <typename ArrayValueType>
bool sparray<ArrayValueType>::empty() const
{
if (arr1d.empty()) return true;
else return false;
}
template <typename ArrayValueType>
int sparray<ArrayValueType>::size() const
{
if (arr1d.empty()) return 0;
else return arr1d.size();
}
/**
* @brief
*
* @return
*/
template <typename ArrayValueType>
int sparray<ArrayValueType>::capcity() const
{
return full_length;
}
template <typename ArrayValueType>
ArrayValueType sparray<ArrayValueType>::zero_value() const
{
return zero_val;
}
/**
* @brief
*
*/
template <typename ArrayValueType>
void sparray<ArrayValueType>::show_list(int st_id, int ed_id) const
{
if (ed_id == 0)
ed_id = arr1d.size();
for (int i = st_id; i < ed_id; i++)
{
std::cout << "( " << arr1d[i].id << ", " << arr1d[i].val << ")" << std::endl;
}
return;
}
/**
* @brief
*/
template <typename ArrayValueType>
void sparray<ArrayValueType>::show_full() const
{
int st = 0;
for (int i = 0; i < arr1d.size(); i++)
{
for (int s = st; s < arr1d[i].id; s++)
std::cout << zero_val << " ";
std::cout << arr1d[i].val << " ";
st = arr1d[i].id+1;
}
if (st <= full_length-1)
{
for (int s = st; s < full_length; s++)
std::cout << zero_val << " ";
}
std::cout << std::endl;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::export_dense(array<ArrayValueType> &b, double multipler,
value_operator_e type) const
{
std::string err_str;
if (type == AppendVal)
{
if (b.size() != full_length)
{
err_str = "Invalid output array size. From void sparray<T>::export_dense(...)";
throw runtime_error(err_str);
}
for (int i = 0; i < arr1d.size(); i++)
{
b.at(arr1d[i].id) += arr1d[i].val * multipler;
}
}
else if (type == ReplaceVal)
{
b.resize(full_length, zero_val);
for (int i = 0; i < arr1d.size(); i++)
{
b.at(arr1d[i].id) = arr1d[i].val * multipler;
}
}
else
{
err_str = "Invalid value type for the output array. From void sparray<T>::export_dense(...)";
throw runtime_error(err_str);
}
return;
}
template <typename ArrayValueType>
void sparray<ArrayValueType>::copy_to(sparray<ArrayValueType> &b, double multipler) const
{
if (!b.empty()) b.clear();
b.malloc(full_length, zero_val);
for (int i = 0; i < arr1d.size(); i++)
{
b.insert(arr1d[i].id, multipler*arr1d[i].val);
}
return;
}
/******************************/
/* 以下是类的私有函数 */
/******************************/
template <typename ArrayValueType>
typename std::vector<arr_node<ArrayValueType> >::iterator sparray<ArrayValueType>::find_iterator(int in_id)
{
if (in_id == arr1d.front().id)
return arr1d.begin();
else if (in_id < arr1d.front().id)
return arr1d.end();
else if (in_id == arr1d.back().id)
return --arr1d.end();
else if (in_id > arr1d.back().id)
return arr1d.end();
else
{
typename std::vector<arr_node<ArrayValueType> >::iterator l_iter = arr1d.begin(), c_iter;
int l_id = 0, u_id = arr1d.size()-1;
int jump_size;
while (u_id-l_id > 1)
{
jump_size = (u_id-l_id)/2;
c_iter = l_iter + jump_size;
if (c_iter->id == in_id)
{
return c_iter;
}
else if (c_iter->id > in_id)
{
u_id -= jump_size;
}
else if (c_iter->id < in_id)
{
l_id += jump_size;
l_iter = c_iter;
}
}
return arr1d.end();
}
}
template <typename ArrayValueType>
typename std::vector<arr_node<ArrayValueType> >::const_iterator
sparray<ArrayValueType>::find_const_iterator(int in_id) const
{
if (in_id == arr1d.front().id)
return arr1d.begin();
else if (in_id < arr1d.front().id)
return arr1d.end();
else if (in_id == arr1d.back().id)
return --arr1d.end();
else if (in_id > arr1d.back().id)
return arr1d.end();
else
{
typename std::vector<arr_node<ArrayValueType> >::const_iterator l_iter = arr1d.begin(), c_iter;
int l_id = 0, u_id = arr1d.size()-1;
int jump_size;
while (u_id-l_id > 1)
{
jump_size = (u_id-l_id)/2;
c_iter = l_iter + jump_size;
if (c_iter->id == in_id)
{
return c_iter;
}
else if (c_iter->id > in_id)
{
u_id -= jump_size;
}
else if (c_iter->id < in_id)
{
l_id += jump_size;
l_iter = c_iter;
}
}
return arr1d.end();
}
}
template <typename ArrayValueType>
typename std::vector<arr_node<ArrayValueType> >::iterator sparray<ArrayValueType>::find_gap(int in_id)
{
if (in_id < arr1d.front().id)
return arr1d.end();
else if (in_id > arr1d.back().id)
return arr1d.end();
typename std::vector<arr_node<ArrayValueType> >::iterator l_iter = arr1d.begin(), c_iter;
int l_id = 0, u_id = arr1d.size()-1;
int jump_size;
while (u_id-l_id > 0)
{
jump_size = (u_id-l_id)/2;
c_iter = l_iter + jump_size;
if (c_iter->id < in_id && in_id < (c_iter+1)->id)
{
return c_iter+1;
}
else if (c_iter->id > in_id)
{
u_id -= jump_size;
}
else if ((c_iter+1)->id < in_id)
{
l_id += jump_size;
l_iter = c_iter;
}
}
return arr1d.end();
}
/******************以下是基于sparray的sparray2d类型********************/
/**
* @brief
*
* sparray2d主要基于向量实现
*
* 访
* 访使
*
* O(logN)O(2*logN)
* 使
*
*
* @tparam ArrayValueType
*/
template <typename ArrayValueType>
class sparray2d
{
private:
std::vector<sparray<ArrayValueType> > arr2d;
ArrayValueType zero_val;
int full_rlength, full_clength;
public:
sparray2d();
sparray2d(int rnum, int cnum, ArrayValueType null_val);
~sparray2d();
void malloc(int rnum, int cnum, ArrayValueType null_val);
void clear();
sparray<ArrayValueType> *at(unsigned int index);
int size();
};
template <typename ArrayValueType>
sparray2d<ArrayValueType>::sparray2d()
{
full_rlength = full_clength = 0;
}
template <typename ArrayValueType>
sparray2d<ArrayValueType>::sparray2d(int rnum, int cnum, ArrayValueType null_val)
{
malloc(rnum, cnum, null_val);
}
template <typename ArrayValueType>
sparray2d<ArrayValueType>::~sparray2d()
{
clear();
}
template <typename ArrayValueType>
void sparray2d<ArrayValueType>::malloc(int rnum, int cnum, ArrayValueType null_val)
{
if (rnum <= 0 || cnum <= 0)
{
std::string err_str = "Invalid matrix size. From void spmatrix<T>::malloc(...)";
throw runtime_error(err_str);
}
full_rlength = rnum; full_clength = cnum;
zero_val = null_val;
arr2d.resize(rnum);
for (int i = 0; i < rnum; i++)
{
arr2d[i].malloc(cnum, null_val);
}
return;
}
template <typename ArrayValueType>
void sparray2d<ArrayValueType>::clear()
{
full_rlength = full_clength = 0;
for (int i = 0; i < arr2d.size(); i++)
{
arr2d[i].clear();
}
arr2d.clear();
std::vector<sparray<ArrayValueType> >().swap(arr2d);
return;
}
template <typename ArrayValueType>
sparray<ArrayValueType> *sparray2d<ArrayValueType>::at(unsigned int index)
{
return &arr2d[index];
}
template <typename ArrayValueType>
int sparray2d<ArrayValueType>::size()
{
return arr2d.size();
}
}
#endif // _GCTL_SPARRAY_H