1 C++中使用vector来表示二维数组

  • 声明一个二维数组:
  1. vector<vector<int>> dp(row, vector<int>(col));

将变量dp初始化为一个含有row个元素的vector对象,其中每个元素又都是含有col个元素的vector对象。内部的vector对象的基类型为int,外部vector对象的基类型为 vector< int >。

  • 获取数组的row和col
  1. vector<vector<int>>& grid
  2. int row = grid.size();
  3. int col = grid.at(0).size();

2 自己动手写一个Grid类

尽管使用嵌套的vector对象能够代表二维数组,但是这种方法很不便利,因此考虑到自己写一个Grid类。

  • 代码实现

开发环境:VS2017

  1. /*
  2. 以Class Template的形式实现Matrix
  3. */
  4. #pragma once
  5. template <typename ValueType>
  6. class Grid
  7. {
  8. public:
  9. class GridRow;
  10. Grid(); //默认的构造函数
  11. Grid(int row,int col);
  12. ~Grid();
  13. int numRows() const;
  14. int numCols() const;
  15. void resize(int row,int col);
  16. bool inBounds(int row, int col) const;
  17. ValueType get(int row, int col);
  18. const ValueType& get(int row, int col) const;
  19. void set(int row, int col, ValueType value);
  20. GridRow operator[](int row);
  21. const GridRow operator[](int row) const;
  22. void deepCopy(const Grid& src)
  23. {
  24. int n = src.m_icol * src.m_irow;
  25. this->element = new ValueType[n];
  26. for(int i = 0;i < n;i++)
  27. {
  28. this->element[i] = src.element[i];
  29. }
  30. this->m_icol = src.m_icol;
  31. this->m_irow = src.m_irow;
  32. }
  33. Grid & operator=(const Grid& src)
  34. {
  35. if (this != &src)
  36. {
  37. delete[] this->element;
  38. deepCopy(src);
  39. }
  40. return *this;
  41. }
  42. Grid(const Grid& src)
  43. {
  44. deepCopy(src);
  45. }
  46. Grid<ValueType> operator +(const Grid<ValueType> & m1);
  47. Grid<ValueType> operator *(const Grid<ValueType>& m1);
  48. ValueType& operator()(int row, int col);
  49. void print() const;
  50. public:
  51. class iterator : public std::iterator<std::input_iterator_tag,ValueType>
  52. {
  53. public:
  54. iterator(const Grid* gp,int index)
  55. {
  56. this->gp = gp;
  57. this->index = index;
  58. }
  59. //拷贝构造函数
  60. iterator(const iterator& it)
  61. {
  62. this->gp = it.gp;
  63. this->index = it.index;
  64. }
  65. iterator& operator++()
  66. {
  67. index++;
  68. return *this;
  69. }
  70. iterator operator++(int)
  71. {
  72. iterator copy(*this);
  73. operator++();
  74. return copy;
  75. }
  76. bool operator==(const iterator& rhs)
  77. {
  78. return (rhs.gp == this->gp) && (rhs.index == this->index);
  79. }
  80. bool operator!=(const iterator& rhs)
  81. {
  82. return !(*this == rhs);
  83. }
  84. ValueType& operator*()
  85. {
  86. return gp->element[index];
  87. }
  88. ValueType* operator->()
  89. {
  90. return &gp->element[index];
  91. }
  92. private:
  93. const Grid* gp; //指向cosnt Grid的指针,让编译器知道迭代器的操作不能改变Grid对象本身
  94. int index;
  95. };
  96. iterator begin() const
  97. {
  98. return iterator(this, 0);
  99. }
  100. iterator end() const
  101. {
  102. return iterator(this, this->m_icol * this->m_irow);
  103. }
  104. private:
  105. /*定义一个嵌套类*/
  106. class GridRow
  107. {
  108. friend class Grid;
  109. public:
  110. ValueType& operator[](int col)
  111. {
  112. if (gp->inBounds(row,col))
  113. {
  114. return gp->element[row * gp->m_icol + col];
  115. }
  116. //else 情况下没有返回值!
  117. }
  118. ValueType operator[](int col) const
  119. {
  120. if (gp->inBounds(row, col))
  121. {
  122. return gp->element[row * gp->m_icol + col];
  123. }
  124. }
  125. private:
  126. GridRow(const Grid* girdRef, int index)
  127. {
  128. gp = const_cast<Grid*>(girdRef);
  129. row = index;
  130. }
  131. GridRow(Grid* girdRef, int index)
  132. {
  133. gp = girdRef;
  134. row = index;
  135. }
  136. Grid* gp;
  137. int row;
  138. };
  139. friend class GridRow;
  140. private:
  141. int m_irow;
  142. int m_icol;
  143. ValueType* element;
  144. };
  145. template<typename ValueType>
  146. Grid<ValueType>::Grid()
  147. {
  148. this->element = NULL;
  149. this->m_irow = 0;
  150. this->m_icol = 0;
  151. }
  152. template<typename ValueType>
  153. Grid<ValueType>::Grid(int row, int col):m_irow(row),m_icol(col)
  154. {
  155. if (row < 0 || col < 0)
  156. {
  157. //error
  158. }
  159. this->element = NULL;
  160. resize(this->m_irow,this->m_icol);
  161. }
  162. template<typename ValueType>
  163. Grid<ValueType>::~Grid()
  164. {
  165. if (this->element != NULL)
  166. {
  167. delete []this->element; //这里恐怕会出错
  168. }
  169. }
  170. template<typename ValueType>
  171. void Grid<ValueType>::resize(int row, int col)
  172. {
  173. if (this->element != NULL)
  174. {
  175. delete[]this->element;
  176. }
  177. this->element = new ValueType[row * col];
  178. this->m_icol = col;
  179. this->m_irow = row;
  180. for (int i = 0;i < row * col;i++)
  181. {
  182. this->element[i] = ValueType();
  183. }
  184. }
  185. template<typename ValueType>
  186. inline bool Grid<ValueType>::inBounds(int row, int col) const
  187. {
  188. /*对row 和 col 的上下边界都有进行检查*/
  189. return (row >= 0 && col >= 0) && (row < this->m_irow && col < this->m_icol);
  190. }
  191. template<typename ValueType>
  192. int Grid<ValueType>::numRows() const
  193. {
  194. return this->m_irow;
  195. }
  196. template<typename ValueType>
  197. int Grid<ValueType>::numCols() const
  198. {
  199. return this->m_icol;
  200. }
  201. template<typename ValueType>
  202. ValueType Grid<ValueType>::get(int row, int col)
  203. {
  204. if (row > this->m_irow || col > this->m_icol || row < 0 || col < 0)
  205. {
  206. //error
  207. }
  208. return this->element[row * this->m_irow + col];
  209. }
  210. template<typename ValueType>
  211. const ValueType & Grid<ValueType>::get(int row, int col) const
  212. {
  213. if (row > this->m_irow || col > this->m_icol || row < 0 || col < 0)
  214. {
  215. //error
  216. }
  217. return this->element[row * this->m_irow + col];
  218. }
  219. template<typename ValueType>
  220. void Grid<ValueType>::set(int row, int col, ValueType value)
  221. {
  222. if (this->element == NULL)
  223. {
  224. //error
  225. }
  226. this->element[row * this->m_icol + col] = value;
  227. }
  228. template<typename ValueType>
  229. typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row)
  230. {
  231. std::cout << typeid(this).name() << std::endl;
  232. return GridRow(this,row);
  233. }
  234. template<typename ValueType>
  235. const typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row) const
  236. {
  237. std::cout << typeid(this).name() << std::endl;
  238. return GridRow(this,row);
  239. }
  240. template<typename ValueType>
  241. Grid<ValueType> Grid<ValueType>::operator+(const Grid<ValueType>& m1)
  242. {
  243. //TODO:确定m1和this的大小相同 若不相同 error
  244. Grid<ValueType> result(m1.m_irow,m1.m_icol);
  245. int grid_size = m1.m_icol * m1.m_irow;
  246. for (int i = 0;i < grid_size;i++)
  247. {
  248. result.element[i] = this->element[i] + m1.element[i];
  249. }
  250. return result;
  251. }
  252. template<typename ValueType>
  253. Grid<ValueType> Grid<ValueType>::operator*(const Grid<ValueType>& m1)
  254. {
  255. //TODO:两个矩阵相乘
  256. //Grid<ValueType> result(this->m_irow,m1.m_icol);
  257. //for (int i = 0;i < result.m_irow;i++)
  258. //{
  259. // for (int j = 0;j < result.m_icol;j++)
  260. // {
  261. // result.set(i,j,0);
  262. // for (int k = 0; k < this->m_icol;k++)
  263. // {
  264. // //result
  265. // }
  266. // }
  267. //}
  268. }
  269. template<typename ValueType>
  270. ValueType& Grid<ValueType>::operator()(int row, int col)
  271. {
  272. return this->element[row * this->m_irow + this->m_icol];
  273. //return this->get(row, col);
  274. }
  275. template<typename ValueType>
  276. void Grid<ValueType>::print() const
  277. {
  278. int col = this->m_icol;
  279. int grid_size = this->m_icol * this->m_irow;
  280. for (int i = 0; i < grid_size; ++i)
  281. {
  282. if (i % col == 0)
  283. {
  284. std::cout << std::endl;
  285. }
  286. std::cout << this->element[i] << " ";
  287. }
  288. }

测试代码:

  1. #include "pch.h"
  2. #include <iostream>
  3. #include "grid.h"
  4. using namespace std;
  5. int main()
  6. {
  7. Grid<double> grid1; //声明一个double类型的数组
  8. Grid<int> grid(2,2);
  9. cout << "row = " << grid.numRows() << endl;
  10. cout << "col = " << grid.numCols() << endl;
  11. grid.resize(3, 3);
  12. cout << "row = " << grid.numRows() << endl;
  13. cout << "col = " << grid.numCols() << endl;
  14. grid.set(0, 0, 1);
  15. grid.set(0, 1, 2);
  16. grid.set(0, 2, 3);
  17. grid.set(1, 0, 4);
  18. grid.set(1, 1, 1);
  19. grid.set(1, 2, 2);
  20. grid.set(2, 0, 3);
  21. grid.set(2, 1, 4);
  22. grid.set(2, 2, 4);
  23. cout << "单个读取元素:" << endl;
  24. cout << grid.get(0, 0)
  25. << grid.get(0, 1)
  26. << grid.get(0, 2) << endl;
  27. cout << "[][]的测试" << endl;
  28. cout << grid[0][0]
  29. << grid[0][1]
  30. << grid[0][2] << endl;
  31. grid[0][0] = 5;
  32. cout << grid[0][0] << endl;
  33. grid.print();
  34. if (grid.inBounds(4,4))
  35. {
  36. cout << "\ngrid中(4,4)存在元素" << endl;
  37. }
  38. else
  39. {
  40. cout << "\ngrid中(4,4)不存在元素" << endl;
  41. }
  42. cout << "grid中(0,2)元素为 " << grid.get(0, 2) << endl;
  43. const Grid<int> grid2(grid); //调用拷贝构造函数
  44. const Grid<int>* a;
  45. a = &(grid2);
  46. cout << "单个读取元素:" << endl;
  47. cout << grid.get(2, 0)
  48. << grid.get(2, 1)
  49. << grid.get(2, 2) << endl;
  50. //grid2.print();
  51. cout << "[][]的测试" << endl;
  52. cout << grid2[0][0]
  53. << grid2[0][1]
  54. << grid2[0][2] << endl;
  55. Grid<int>::iterator it = grid.begin();
  56. cout << *(it) << endl;
  57. it++;
  58. cout << *(it) << endl;
  59. Grid<int>::iterator it1 = grid2.begin();
  60. if (it != it1)
  61. {
  62. cout << "it != it1" << endl;
  63. }
  64. return 0;
  65. }

测试的方法是“单元测试”,尽量把每一个函数功能都测试到,上述测试代码的运行截图:

  • 上述代码的不足与问题:

1 测试代码并没有把所有的函数功能都测试到。

2 矩阵相乘的函数没有实现完整。

3 Grid类中的get(),set(),operator [ ](int row)等函数需要做输入参数的检查,当输入的row或col超出范围时应有错误提示。

4 Grid类中的迭代器实现的功能不足。

以下为在调试代码中遇到的错误:

  • 错误的复现

在VS2017中

  1. const int num = 10;
  2. int *p = &num; //编译器报错

必须要把上面的代码修改为:

  1. const int num = 10;
  2. const int *p = &num;

在今天的测试代码中,有如下一行代码,声明了一个const Grid类型的变量grid2:

  1. const Grid<int> grid2(grid); //调用拷贝构造函数

然后测试运算符[][],测试代码如下:

  1. cout << grid2[0][0]
  2. << grid2[0][1]
  3. << grid2[0][2] << endl;

此时VS2017编译器报错:

错误 C2440 无法从“initializer list”转换为“Grid::GridRow”

这个错误很奇怪,根据错误提示:初始化列表无法转换为Grid< int >::GridRow。把这段代码放到gcc中编译调试也会报错。

  • 错误的分析

加断点调试,上述测试代码会首先跳到下面的代码里:

  1. template<typename ValueType>
  2. typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row)
  3. {
  4. std::cout << typeid(this).name() << std::endl;
  5. return GridRow(this,row);
  6. }
  7. template<typename ValueType>
  8. const typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row) const
  9. {
  10. std::cout << typeid(this).name() << std::endl;
  11. return GridRow(this,row);
  12. }

接下来追到GridRow()这个构造函数里,函数实现如下:

  1. GridRow(Grid* girdRef, int index)
  2. {
  3. gp = girdRef;
  4. row = index;
  5. }

函数调用的流程大致如上分析。下面看错误的具体分析

声明了const Grid< int > grid2的类型,由于grid2是const object,所以系统调用的应该是下面这个函数:

  1. template<typename ValueType>
  2. const typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row) const
  3. {
  4. std::cout << typeid(this).name() << std::endl;
  5. return GridRow(this,row);
  6. }

在这个函数里,this的类型应该是class Grid< int > const *, 调用GridRow()函数,但是这个函数的第一个参数是Grid * 类型的,也就是说把Grid< int > const * 转换为Grid< int > *,这个时候编译器就会报错。

  • 错误的解决

给GridRow类声明两个构造函数,这两个构造函数分别如下:

  1. GridRow(const Grid* girdRef, int index)
  2. {
  3. gp = const_cast<Grid*>(girdRef);
  4. row = index;
  5. }
  6. GridRow(Grid* girdRef, int index)
  7. {
  8. gp = girdRef;
  9. row = index;
  10. }

这样class Grid < int > const*就会调用第一个构造函数,因此也不会报错。

  • 参考资料:

    1 《C++程序设计 基础,编程抽象与算法策略》

    2 《Essential C++》

C++中vecotr表示二维数组并自己实现一个Grid类的更多相关文章

  1. C语言中如何将二维数组作为函数的参数传递

    今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不 ...

  2. 以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

    学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简 ...

  3. C++中动态申请二维数组并释放方法

    C/C++中动态开辟一维.二维数组是非常常用的,以前没记住,做题时怎么也想不起来,现在好好整理一下. C++中有三种方法来动态申请多维数组 (1)C中的malloc/free (2)C++中的new/ ...

  4. 如何在C++中动态建立二维数组(转)

    http://blog.sina.com.cn/s/blog_7c073a8d0100qp1w.html http://blog.163.com/wujiaxing009@126/blog/stati ...

  5. 消除VS中动态申请二维数组C6011,C6385,C6386的警告

    动态申请二维数组,无非就是通过指针来实现.@wowpH 过程分三步:1.申请内存,2.使用数组,3.释放内存. 代码如下: /************************************* ...

  6. OpenCV中Mat与二维数组之间的转换

    ---恢复内容开始--- 在OpenCV中将Mat(二维)与二维数组相对应,即将Mat中的每个像素值赋给一个二维数组. 全部代码如下: #include <iostream> #inclu ...

  7. Python创建二维数组(关于list的一个小坑)

    0.目录 1.遇到的问题 2.创建二维数组的办法 3.1 直接创建法 3.2 列表生成式法 3.3 使用模块numpy创建 1.遇到的问题 今天写Python代码的时候遇到了一个大坑,差点就耽误我交作 ...

  8. PHP中如何对二维数组按某个键值进行排序

    $arr=[     array(         'name'=>'张三',         'age'=>28     ),     array(         'name'=> ...

  9. 《剑指offer》 二维数组中的查找

    本题目是<剑指offer>中的题目 二维数组中的查找 题目: 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个 ...

随机推荐

  1. from sklearn import datasets运行错误:ImportError: DLL load failed: 找不到指定的程序------解决办法

    在运行集成学习的多数投票分类代码时,出现错误 from sklearn import datasets from sklearn.model_selection import cross_val_sc ...

  2. 九、设置RF自定义的日志输出路径

    在Arguments输入-d E:\\robot,每次运行完都会发送该目录日志

  3. Selenium IDE安装及环境搭建教程

    摘自https://blog.csdn.net/ywyxb/article/details/59103683 Selenium IDE环境部署- Firefox浏览器Firefox-ESR版本下载(推 ...

  4. java常用加密算法

    常用加密算法的Java实现(一) ——单向加密算法MD5和SHA 日期:2014/6/1 文:阿蜜果 1.Java的安全体系架构 1.1           Java的安全体系架构介绍 Java中为安 ...

  5. ssh config高级用法

    转载自:Chapter 7. Advanced Client Use 1. 配置文件 ssh1和Openssh的配置文件在.ssh/ssh_config ssh2配置文件在.ssh2/ssh2_con ...

  6. 阶段3 1.Mybatis_04.自定义Mybatis框架基于注解开发_3 基于注解的自定义再分析

    这里只需要 一是连接数据库的 二是映射的 注解是class的方式  dom4j技术获取xml的数据,这是xml的方式获取的下面几个关键的点 注解的方式回去dao类里面的几个主要的信息 User黄色的部 ...

  7. Ajax请求Json数据,报500错误,后台没有错误日志。

    post请求:http://localhost:9080/DataDiscoveryWeb/issueformcount/queryIssueTendencyDetail.xhtml?jobId=86 ...

  8. Python学习之==>常用模块

    一.string模块 import string print(string.ascii_letters) # 所有大小写字母 print(string.ascii_lowercase) # 所有小写字 ...

  9. Chapter03 第二节 const限定符的使用

    3.2 const限定符 const的作用:替代#define作为有类型检查的常量来使用.他的值被初始化后就固定了,成为一个只读变量,不能更改.(推荐使用特殊的命名规范来区分常量和非常量). cons ...

  10. angular5 给元素添加自定义属性

    今天尝试给一个a 标签添加一个自定义属性,用于存放相关数据,但是angular templates 编译不通过. <a href="javascript:void(0);" ...