valarray容器
严格来说,在标准库中,有两种”非STL“(因为这两种容器中没有一种能够完全满足STL容器的要求)容器:bitset,valarray。之所以将bitset称为非STL容器,是因为其不允许对其成员进行直接寻址。
valarray是一个类-vector的容器。其大多数函数和运算符都将valarray作为一个整体来进行操作。
#include <valarray>
#include <iostream>
#include <cstddef>
using namespace std;
double f(double x) { return 2.0 * x - 1.0; }
template<class T>
void print(const char* lbl,const std::valarray<T>& a) {
std::cout << lbl << ": ";
for(std::size_t i = 0; i < a.size(); ++i)
std::cout << a[i] << ' ';
std::cout << std::endl;
}
int main() {
double n[] = { 1.0, 2.0, 3.0, 4.0 };
valarray<double> v(n, sizeof n / sizeof n[0]);
print("v", v);
valarray<double> sh(v.shift(1));//左移
print("shift 1", sh);
valarray<double> acc(v + sh);//相加
print("sum", acc);
valarray<double> trig(sin(v) + cos(acc));//数学函数
print("trig", trig);
valarray<double> p(pow(v, 3.0));//立方
print("3rd power", p);
valarray<double> app(v.apply(f));//为每一个元素应用一个函数
print("f(v)", app);
valarray<bool> eq(v == app);
print("v == app?", eq);
double x = v.min();
double y = v.max();
double z = v.sum();
cout << "x = " << x << ", y = " << y
<< ", z = " << z << endl;
} ///:~
从上面可以看出,valarray的操作有很多,很多常用的数学函数都集成在一起,很方便操作。此外,valarray还在如下一些操作。
apply cshift fill free max min operator T * operator!
operator%= operator&= operator>>= operator<<= operato r*=
operator+ operator+= operator- operator-= operator/= operator=
operator[ ] operator^= operator|= operator~ resize shift size
sum valarray value_type
explicit valarray(size_t n);
valarray(const T& val, size_t n));
valarray(const T *p, size_t n);
valarray(const slice_array<T>& sa);
valarray(const gslice_array<T>& ga);
valarray(const mask_array<T>& ma);
valarray(const indirect_array<T>& ia);
此外,还可以引用元素的一个子集,不仅可以提取信息,而且还可以更新这些信息。valarray的一个子集称为一个切片。如下所示:
class slice {
public:
slice();
slice(size_t st, size_t len, size_t str);//起始索引,长度,间隔
size_t start() const;
size_t size() const;
size_t stride() const;
};
class gslice {
public:
gslice();
gslice(size_t st,
const valarray<size_t> len, const valarray<size_t> str);
size_t start() const;
const valarray<size_t> size() const;
const valarray<size_t> stride() const;
};
如下一个例子:
#include <valarray>
#include <iostream>
#include <cstddef>
using namespace std;
template<class T>
void print(const char* lbl,const std::valarray<T>& a) {
std::cout << lbl << ": ";
for(std::size_t i = 0; i < a.size(); ++i)
std::cout << a[i] << ' ';
std::cout << std::endl;
}
int main() {
int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
valarray<int> v(data, 12);
valarray<int> r1(v[slice(0, 4, 3)]);//1,4,7,10
print("slice(0,4,3)", r1);
// Extract conditionally
valarray<int> r2(v[v > 6]);
print("elements > 6", r2);
// Square first column
v[slice(0, 4, 3)] *= valarray<int>(v[slice(0, 4, 3)]);
print("after squaring first column", v);
// Restore it
int idx[] = { 1, 4, 7, 10 };
valarray<int> save(idx, 4);
v[slice(0, 4, 3)] = save;
print("v restored", v);
// Extract a 2-d subset: { { 1, 3, 5 }, { 7, 9, 11 } }
valarray<size_t> siz(2);
siz[0] = 2;
siz[1] = 3;
valarray<size_t> gap(2);
gap[0] = 6;
gap[1] = 2;
valarray<int> r3(v[gslice(0, siz, gap)]);//siz显示是2×3矩阵,跨距是6和2
print("2-d slice", r3);
} ///:~
A gslice object (for “generalized slice”) is like a slice, except that the
counts and strides are themselves arrays, which means you can interpret a
valarray as a multidimensional array. The example above extracts a 2 by 3
array from v, where the numbers start at zero and the numbers for the first
dimension are found six slots apart in v, and the others two apart, which
effectively extracts the matrix
// Uses valarray to multiply matrices
#include <cassert>
#include <cstddef>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <valarray>
using namespace std;
// Prints a valarray as a square matrix
template<class T>
void printMatrix(const valarray<T>& a, size_t n) {
size_t siz = n*n;
assert(siz <= a.size());
for(size_t i = 0; i < siz; ++i) {
cout << setw(5) << a[i];
cout << ((i+1)%n ? ' ' : '\n');
}
cout << endl;
}
// Multiplies compatible matrices in valarrays
template<class T>
valarray<T>
matmult(const valarray<T>& a, size_t arows, size_t acols,
const valarray<T>& b, size_t brows, size_t bcols) {
assert(acols == brows);
valarray<T> result(arows * bcols);
for(size_t i = 0; i < arows; ++i)
for(size_t j = 0; j < bcols; ++j) {
// Take dot product of row a[i] and col b[j]
valarray<T> row = a[slice(acols*i, acols, 1)];
valarray<T> col = b[slice(j, brows, bcols)];
result[i*bcols + j] = (row * col).sum();
}
return result;
}
int main() {
const int n = 3;
int adata[n*n] = {1,0,-1,2,2,-3,3,4,0};
int bdata[n*n] = {3,4,-1,1,-3,0,-1,1,2};
valarray<int> a(adata, n*n);
valarray<int> b(bdata, n*n);
valarray<int> c(matmult(a, n, n, b, n, n));
printMatrix(c, n);
} ///:~