本篇通过自定义数组类模板,实现python列表的绝大部分函数,包括:
以及numpy中的arange函数
涉及到的知识点有:
头文件myArray.hpp代码如下:
#pragma once
#include <iostream>
using namespace std;
//因为 int len(MyArray<T>& arr) 在类定义之前,需要提前让编译器知道MyArray是一个类模板
template <class T>
class MyArray;
//友元函数模板类外实现,需要让编译器提前知道它的存在
template<class T>
int len(MyArray<T>& arr)
{
return arr.m_length;
}
//友元函数模板类外实现,需要让编译器提前知道它的存在
//重载<<
template<class T>
ostream & operator<<(ostream& out, MyArray<T>& arr)
{
cout<<'[';
int j=1;
if (len(arr)>0)
{
for(int i=0; i< arr.m_length-1; i++)
{
out<< arr.pAddress[i]<<",";
//if(j%20==0) out<<endl;
j++;
}
out<< arr.pAddress[arr.m_length-1];
}
cout<<']';
return out;
}
template<class T>
ostream & operator<<(ostream& out, MyArray<T>&& arr)
{
cout<<'[';
int j=1;
if (len(arr)>0)
{
for(int i=0; i< arr.m_length-1; i++)
{
out<< arr.pAddress[i]<<",";
//if(j%20==0) out<<endl;
j++;
}
out<< arr.pAddress[arr.m_length-1];
}
cout<<']';
return out;
}
template<typename T>
MyArray<T>& arange(T start, T stop, T step)
{
if(step >0)
{
if(start>= stop)
{
MyArray<T>* p = new MyArray<T>;
return *p;
}
int n=0;
T x = start;
while(x < stop)
{
n++;
x += step;
}
MyArray<T>* p = new MyArray<T>(n);
p->m_length = n;
for(int i=0; i<n; i++)
{
p->pAddress[i] = start + i*step;
}
return *p;
}
else if(step<0)
{
if(start<= stop)
{
MyArray<T>* p = new MyArray<T>;
return *p;
}
int n=0;
T x = start;
while(x > stop)
{
n++;
x += step;
}
MyArray<T>* p = new MyArray<T>(n);
p->m_length = n;
for(int i=0; i<n; i++)
{
p->pAddress[i] = start + i*step;
}
return *p;
}
else throw invalid_argument("step cannot be zero");
}
template <class T>
class MyArray
{
friend int len<>(MyArray<T>& arr);//友元函数模板类外实现的类内声明,需要加空模板参数列表
friend ostream & operator<<<>(ostream& out, MyArray<T>& arr);
friend ostream & operator<<<>(ostream& out, MyArray<T>&& arr);
friend MyArray<T>& arange<>(T start, T stop, T step);
public:
MyArray(int length)
{
//cout <<"MyArray有参构造函数的调用"<<endl;
//cout<<"T的实际类型是 "<<typeid(T).name()<<endl;
if(length< 0) throw invalid_argument("length should not be negative");
else if (length == 0) this->pAddress = NULL;
else this->pAddress = new T[length];
this->m_length = length;
}
MyArray()
{
//cout <<"MyArray无参构造函数的调用"<<endl;
this->pAddress = NULL;
this->m_length = 0;
}
MyArray(MyArray& arr)
{
//cout <<"MyArray拷贝构造函数的调用"<<endl;
this->m_length = arr.m_length;
this->pAddress = new T[this->m_length];//深拷贝
for(int i=0; i< this->m_length; i++)//复制数组内容
{
this->pAddress[i] = arr.pAddress[i];
}
}
//重载赋值操作符,防止浅拷贝问题
MyArray& operator=(const MyArray& arr)
{
//cout<<"赋值操作符的重载"<<endl;
//如果原来堆区有数据,需要先释放
if(this->pAddress != NULL)
{
delete [] pAddress;
}
this->m_length = arr.m_length;
this->pAddress = new T[arr.m_length];//深拷贝
for(int i=0; i< this->m_length; i++)//复制数组内容
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
~MyArray()
{
//cout <<"MyArray析构函数的调用"<<endl;
if(this->pAddress != NULL)
{
delete [] this->pAddress;
pAddress = NULL;
this->m_length = 0;
}
}
T& operator[](int index)//注意返回引用,否则不能当左值
{
//索引转换,负数索引转换到0 ~ length-1 区间
if (0 <= index && index < this->m_length)
return this->pAddress[index];
else if (-this->m_length <= index && index < 0)
{
int index_;
index_ = index + this->m_length;
return this->pAddress[index_];
}
else throw invalid_argument("index out of range");
}
MyArray& sort(bool reversed=false)
{
//冒泡排序
T* p = this->pAddress;
T temp;
if(reversed)
{
for(int i = 0; i < this->m_length; i++)
{
for(int j = 0; j < this->m_length -1 -i; j++)
{
if(p[j] < p[j+1])
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
else
{
for(int i = 0; i < this->m_length; i++)
{
for(int j = 0; j < this->m_length -1 -i; j++)
{
if(p[j] > p[j+1])
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
return *this;
}
T max()
{
T max_ = this->pAddress[0];
for(int i = 1; i < this->m_length; i++)
{
if (this->pAddress[i] > max_) max_ = this->pAddress[i];
}
return max_;
}
T min()
{
T min_ = this->pAddress[0];
for(int i = 1; i < this->m_length; i++)
{
if (this->pAddress[i] < min_) min_ = this->pAddress[i];
}
return min_;
}
int count(T value)
{
int qty = 0;
for(int i = 0; i < this->m_length; i++)
{
if (value == this->pAddress[i]) qty++;
}
return qty;
}
void append(T value)
{
T* p = new T[this->m_length + 1];
if(this->pAddress != NULL)
{
for(int i=0; i< this->m_length; i++)//复制原数组内容
{
p[i] = this->pAddress[i];
}
p[this->m_length] = value;
delete [] this->pAddress;
this->pAddress = p;
}
else
{
this->pAddress = new T[1];
this->pAddress[0] = value;
}
this->m_length ++;
}
void insert(int index, T value)
{
//在index前插入值
int index_;
if (0 <= index && index < this->m_length)
index_ = index;
else if (-this->m_length <= index && index < 0)
index_ = index + this->m_length;
else throw invalid_argument("index out of range");
T* p = new T[this->m_length + 1];
for(int i=0; i<index_; i++)
p[i] = this->pAddress[i];
for(int i=index_; i< this->m_length; i++)
p[i+1] = this->pAddress[i];
p[index_] = value;
this->pAddress = p;
this->m_length++;
}
T pop(int index=-1)
{
if(this->pAddress == NULL)
throw invalid_argument("No element in array");
int index_;
if (0 <= index && index < this->m_length)
index_ = index;
else if (-this->m_length <= index && index < 0)
index_ = index + this->m_length;
else throw invalid_argument("index out of range");
T temp = this->pAddress[index_];
T* p = new T[this->m_length - 1];
for(int i=0; i<index_; i++)
p[i] = this->pAddress[i];
for(int i=index_+1; i< this->m_length; i++)
p[i-1] = this->pAddress[i];
this->pAddress = p;
this->m_length--;
if(this->m_length==0)
{
delete[] this->pAddress;
this->pAddress = NULL;
}
return temp;
}
void remove(T value)
{
//移除第一次出现的值,若不存在则抛出异常
if(this->pAddress == NULL)
throw invalid_argument("No element in array");
int i;
for(i=0; i < this->m_length; i++)
{
if(value == this->pAddress[i]) break;
}
if(i == this->m_length)
throw invalid_argument("not found");
T* p = new T[this->m_length - 1];
for(int j=0; j<i; j++)
p[j] = this->pAddress[j];
for(int j=i+1; j< this->m_length; j++)
p[j-1] = this->pAddress[j];
this->pAddress = p;
this->m_length--;
if(this->m_length==0)
{
delete[] this->pAddress;
this->pAddress = NULL;
}
}
void extend(MyArray& arr)
{
int total_length = this->m_length + arr.m_length;
T* p = new T[total_length];
if(this->pAddress != NULL)
{
for(int i=0; i< this->m_length; i++)//复制原数组内容
{
p[i] = this->pAddress[i];
}
for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
{
p[this->m_length + i] = arr.pAddress[i];
}
delete [] this->pAddress;
this->pAddress = p;
}
else
{
this->pAddress = new T[arr.m_length];
for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
{
this->pAddress[i] = arr.pAddress[i];
}
}
this->m_length = total_length;
}
int index(T value, int start=0, int stop=-1)
{
//在start和stop之间,找出value第一次出现的index
if(this->pAddress == NULL)
throw invalid_argument("No element in array");
int start_;
if (0 <= start && start < this->m_length)
start_ = start;
else if (-this->m_length <= start && start < 0)
start_ = start + this->m_length;
else throw invalid_argument("start out of range");
int stop_;
if (0 <= stop && stop < this->m_length)
stop_ = stop;
else if (-this->m_length <= stop && stop < 0)
stop_ = stop + this->m_length;
else throw invalid_argument("stop out of range");
if(start_ >= stop_)
throw invalid_argument("start_ should be less than stop_");
for(int i = start_; i <= stop_; i++)
{
if(value == this->pAddress[i]) return i;
}
throw invalid_argument("not found");
}
MyArray& reverse()
{
if(this->pAddress!= NULL)
{
T temp;
int mirrored;
for(int i=0; i< this->m_length / 2; i++)
{
mirrored = this->m_length-1 - i;
temp = this->pAddress[i];
this->pAddress[i] = this->pAddress[mirrored];
this->pAddress[mirrored] = temp;
}
}
return *this;
}
bool operator==(MyArray& arr)
{
if (this->m_length != arr.m_length) return false;
for(int i; i < arr.m_length; i++)
{
if(this->pAddress[i] != arr.pAddress[i]) return false;
}
return true;
}
bool operator!=(MyArray& arr)
{
if (this->m_length != arr.m_length) return true;
for(int i; i < arr.m_length; i++)
{
if(this->pAddress[i] != arr.pAddress[i]) return true;
}
return false;
}
MyArray operator+(MyArray& arr)
{
int total_length = this->m_length + arr.m_length;
MyArray<T> sum(total_length);
for(int i=0; i< this->m_length; i++)//复制原数组内容
{
sum.pAddress[i] = this->pAddress[i];
}
for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
{
sum.pAddress[this->m_length + i] = arr.pAddress[i];
}
return sum;
}
MyArray operator*(int n)
{
if(n <0) throw invalid_argument("n should not be negative");
if (n==0)
{
MyArray<T> sum;
return sum;
}
int total_length = this->m_length * n;
MyArray<T> sum(total_length);
for(int k=0; k < n; k++)
{
for(int i=0; i< this->m_length; i++)//复制原数组内容
{
sum.pAddress[k* this->m_length + i] = this->pAddress[i];
}
}
return sum;
}
int convert_index(int index)
{
//索引转换,负数或者越界的索引转换到0 ~ length 区间
if (index <= -this->m_length) return 0;
else if (index < 0) return this->m_length + index;
else if(index < this->m_length) return index;
else return this->m_length;
}
MyArray sliced(int start, int end, int step)
{
if (step>0)
{
int start_, end_, n_sliced, r ;
start_ = this->convert_index(start);
end_ = this->convert_index(end);
if(start_ >= end_)
{
MyArray<T> nothing;
return nothing;
}
r = (end_ - start_) % step;
if(r==0) n_sliced = (end_ - start_)/ step;
else n_sliced = (end_ - start_)/ step + 1;
MyArray<T> sliced(n_sliced);
for(int i=0; i<n_sliced; i++)
{
int index_ = start_ + i * step;
sliced.pAddress[i] = this->pAddress[index_];
}
return sliced;
}
else if (step<0)
{
int start_, end_, n_sliced, r ;
start_ = this->convert_index(start);
end_ = this->convert_index(end);
if (start_ == this->m_length) start_--;
if(start_ <= end_)
{
MyArray<T> nothing;
return nothing;
}
r = (start_ - end_) % (-step);
if(r==0) n_sliced = (start_ - end_) / (-step);
else n_sliced = (start_ - end_) / (-step) + 1;
MyArray<T> sliced(n_sliced);
for(int i=0; i < n_sliced; i++)
{
int index_ = start_ + i * step;
sliced.pAddress[i] = this->pAddress[index_];
}
return sliced;
}
else throw invalid_argument("slice step cannot be zero");
}
private:
T* pAddress;//指向堆区开辟的数组
int m_length;//数组元素个数
};
测试用的代码如下:
#include<iostream>
#include <time.h>
#include "myArray.hpp"
void test1()
{
MyArray<float> a1(5);
MyArray<float> a2(a1);
MyArray<float> a3 = a1;//这步不会调用operator==,而是调用拷贝构造
MyArray<float> a4(9);
a4 = a1; //这步调用operator=
cout<<"a4==a1:"<< ((a4 == a1)? "true":"false")<<endl;//注意括号提高优先级
cout<<"a2!=a1:"<< ((a2 != a1)? "true":"false")<<endl;//注意括号提高优先级
cout<<true<<endl;
srand(time(0));//设置随时间变化的随机种子
for(int i=0; i < len(a1); i++)
{
a1[i] = rand()%11; //这步调用operator[]
}
cout<<"排序前:"<<endl;
cout<<a1<<endl;
cout <<"max element of a1 = "<< a1.max()<<endl;
cout <<"min element of a1 = "<< a1.min()<<endl;
cout<<"count of 1 in a1 = "<< a1.count(1)<<endl;
a1.sort();
cout<<endl;
cout<<"排序后:"<<endl;
cout<<a1<<endl;
cout<<endl;
a1.append(999.999);
a1.insert(1,999.999);
a1.insert(-1,888.0);
a1.remove(999.999);
a1.remove(999.999);
for(int i=0; i < len(a4); i++)
{
a4[i] = i; //这步调用operator[]
}
a1.extend(a4);
a1.extend(a1);
cout<<a1<<endl;
cout<<"length of a1 = "<< len(a1)<<endl;
cout<<"a1[-1] = "<< a1[-1]<<endl;
cout<<"a1[-22] = "<< a1[-22]<<endl;
cout<<a1.pop()<<endl;
cout<<a1.pop(-2)<<endl;
cout<<a1.pop(0)<<endl;
cout<<"开始打印:"<<endl;
cout<<a1<<endl;
cout<<"a1.index(1): "<<a1.index(1)<<endl;
cout<<"a1.index(1,1,-1): "<<a1.index(1,2,-1)<<endl;
a1.reverse();
cout<<"逆转后:"<<endl;
cout<<a1<<endl;
}
void index_test()
{
MyArray<char> a(6);
a[-1]='f';
a[-2] = 'e';
a[0]= 'a';
a[1]= 'b';
a[2]= 'c';
a[3]= 'd';
cout<<a<<endl;
}
void pop_test()
{
MyArray<int> a(10);
for(int i=0; i < len(a); i++)
{
a[i]=i;
}
cout<<a<<endl;
cout<<len(a)<<endl;
for(int i=0; i < 10; i++)
{
a.pop();
cout<<len(a)<<","<<a<<endl;
}
MyArray<int> b(10);
for(int i=0; i < len(b); i++)
{
b[i]=i;
}
for(int i=0; i < 10; i++)
{
b.pop(0);
cout<<len(b)<<","<<b<<endl;
}
//cout<<a.index(0)<<endl;
}
void add_test()
{
MyArray<int> a(5);
for(int i=0; i < len(a); i++)
{
a[i]=i;
}
MyArray<int> x;
x = a + a + a;
cout <<x<<endl;
MyArray<int> b;
x = b + b;
cout <<x<<endl;
}
void multiply_test()
{
MyArray<int> a(6);
for(int i=0; i < len(a); i++)
{
a[i]=i;
}
MyArray<int> b;
MyArray<int> x;
x = a * 0;
cout <<x<<endl;
x = a * 4;
cout <<x<<endl;
x = b * 2;
cout <<x<<endl;
}
void slice_test()
{
MyArray<int> a(100);
for(int i=0; i < len(a); i++)
{
a[i]=i;
}
cout<<a<<endl;
cout<<a.sliced(-1,1,-3)<<endl;
}
void arange_test()
{
cout<<arange(0.0,10.01,0.2)<<endl;
cout<<arange<float>(0,10,0.2)<<endl;
cout<<arange(9.1,-1.0,-0.2)<<endl;
cout<<arange(0,20,2)<<endl;
//cout<<arange(0,20,0)<<endl;//Exception raised due to zero step
}
int main()
{
index_test();
pop_test();
add_test();
multiply_test();
slice_test();
arange_test();
return 0;
}
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!