使用二级指针生成动态的二维数组,其中数组元素不重复且0<= arr2D[i][j]<len,len是二维数组的行列数之积.
在做这道题之前,我们要先知道,什么叫二级指针,什么叫动态的二维数组,然后再探究怎么生成随机数且让二维数组的元素不重复。
那下面让我们开始探究这些问题吧:
一:什么叫二级指针?
在理解二级指针之前我们先来理解什么叫一级指针,这样便于帮助我们理解二级指针。
一级指针:表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个存放数据的空间。比如 int * p,这个就表示p是一个指针变量,指向的是一个存放int型数据的空间,p存放着该空间的地址。
二级这指针:表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个存放指针的空间,并且指向的这个空间中的指针,指向一个存放数据的空间。简单点理解就是:指向指针的指针。例如:int** p,表示p是一个二级指针变量,指向一个内存空间,p保存着这个内存空间的地址,这个空间用来存放一个指针,所存放的这个指针指向的是存放一个int类型数据的空间。
二:数组和指针的联系
我们知道,数组其实就是一种数据结构,用来存储同一种数据类型的的集合,所有的数组都是由连续的内存位置组成。在c++中,我们可以通过多种方法来对数组进行声明和定义,但是要想得到我们想要长度的数组,即动态数组,则必须要在堆上使用new来开辟一块内存给数组分配空间,这时候我们就需要使用指针来接受new开辟空间后返回的地址。比如我们可以先声明一维数组的长度,int len ,然后再从控制台中输入获得我们想要的len 的值,之后再给一维数组开辟空间 int* p =new int [len],返回得到了一个指向一维数组地址的针指p,之后我们就可以通过这个指针p访问一维数组的元素。如此我们便可以通过指针来指向一个一维数组,从而达到数组的声明和定义的实现。为了防止内存泄露,我们要在使用完了这个动态的一维数组后要注意使用delete [] p;的方式来释放内存。
对于动态的二维数组而言就相对复杂:
首先,我们先声明一个二级指针 int** p = NULL;//必须要先赋值为NULL,否则编译器会报错。
定义 二维数组的行和列的长度;
int low;//行
int row ;//列
然后从控制台中获得输入的 low和row的值。
接着再给二维数组开辟空间:
p = new int*[low];//获得指向一个存放指针的空间
这时p相当于一个一维数组,这个一维数组的长度为low,每个元素是一个指针。然后再开辟一维数组中每个指针所指向的存放int类型数据的空间,并返回该空间的地址给每个指针p[i]。
for (int i = 0; i < low; i++)
{
p[i] = new int[row];
}
这样我们就给一个二维数组开辟了一块完整的空间,并将这个空间的地址保存在了p这个二级指针变量中,我们就可以通过p[i][j]的方式来进行访问这个二维数组中的元素。
动态的二维数组的空间是用new在堆区开辟的,所以在使用完后我们要及时地对这个动态的二维数组的空间进行释放。这个释放的方式跟动态的一维数组的释放方式更复杂。我们可以这么理解:先释放一维数组每个指针指向的内存空间,然后再释放这个一维数组的空间。
即:
//二维数组的释放,先释放二级指针,再释放一级指针
for(i=0; i<m; i++){
delete[] p[i];
}
delete[] p;
如果只有 delete[] p; 则会导致p[i]中每个指针所指向的内存无法释放从而造成内存泄露。因此要特别注意这个事项!
三:生成元素不重复的二维数组:
我们以动态的二位数组 的 low = 3, row =3 ,则len = low * row =9 为例生成元素 arr2D[i][j]不重复且在整数区间[0,9)的二维数组。
我们可以按照以下算法来给得到满足条件的动态二维数组:
(1)首先定义一个长度为len = 9的一位数组arr1D,然后将其元素按顺序从小到大初始化为:0,1,2,3,…, 7,8;
(2)在区间为[0,9)中随机获得一个随机整数 pos作为一维数组的某个下标,将一维数组元素arr1D[pos]赋值给arr2D中的某个元素。然后删除arr1D[pos]这个元素,再将一维数组的长度len减去1,此时len = 8。
(3)这时一维数组arr1D中剩余8个元素且互不重复,接着再在区间为[0,8)中随机获得一个随机整数 pos作为一维数组的某个下标,将一维数组元素arr1D[pos]赋值给arr2D中的某个元素(arr2D中已经被赋值过的元素不需要再赋值)。然后删除arr1D[pos]这个元素,再将一维数组的长度len减去1,此时len = 7。以此类,重复操作,直到一维数组的len =0,即二维数组的每个元素都能被赋值。
例如:
第1次:
arr1D={0,1,2,3,4,5,6,7,8},len=9
int pos =rand()%len;假若[0,len)中的随机数 pos=2;
arr2D[0][0]=arr1D[pos];
则删除arr1D[pos]后,arr1D={0,1,2,4,5,6,7,8},len =8;
第2次:
arr1D={0,1,2,4,5,6,7,8},len=8
int pos =rand()%len;假若[0,len)中的随机数 pos=1;
arr2D[0][1]=arr1D[pos];
则删除arr1D[pos]后,arr1D={0,2,4,5,6,7,8},len =7;
第3次:
arr1D={0,2,4,5,6,7,8},len=7
int pos =rand()%len;假若[0,len)中的随机数 pos=6;
arr2D[0][2]=arr1D[pos];
则删除arr1D[pos]后,arr1D={0,2,4,5,6,7},len =6;
第4次:
arr1D={0,2,4,5,6, 7},len=6
int pos =rand()%len;假若[0,len)中的随机数 pos=3;
arr2D[1][0]=arr1D[pos];
则删除arr1D[pos]后,arr1D={0,2,4,6, 7},len =5;
第5次:
arr1D={0,2,4,6,7},len=5
int pos =rand()%len;假若[0,len)中的随机数 pos=0
arr2D[1][1]=arr1D[pos];
则删除arr1D[pos]后,arr1D={2,4, 6,7},len =4;
第6次:
arr1D={2,4, 6,7},len=4
int pos =rand()%len;假若[0,len)中的随机数 pos=2;
arr2D[1][2]=arr1D[pos];
则删除arr1D[pos]后,arr1D={ 2,4, 7},len =3;
第7次:
arr1D={ 2,4, 7},len =3;
int pos =rand()%len;假若[0,len)中的随机数 pos=1;
arr2D[2][0]=arr1D[pos];
则删除arr1D[pos]后,{ 2,7},len =2;
第8次:
arr1D={ 2,7},len =2;
int pos =rand()%len;假若[0,len)中的随机数 pos=1;
arr2D[2][1]=arr1D[pos];
则删除arr1D[pos]后,arr1D={ 2},len =1;
第9次:
arr1D={ 2},len =1;
int pos =rand()%len;假若[0,len)中的随机数 pos=0;
arr2D[2][2]=arr1D[pos];
则删除arr1D[pos]后,arr1D={},len =0;
到此就完成了满足所需的动态二维数组的赋值。
注意:
数组的元素的删除实际上是数组的拷贝。
其中pos为要删除的元素的索引,len为删除一个元素后的元素个数
for (int m = pos; m < len; m++)
{
arr1D[m] = arr1D[m+1];
}
比如:数组int arr1D={1,5,4,3}删除元素5后其数组变为arr1D={1,4,3 } ,其代码实现为:
for (int m =1; m < 3; m++)
{
arr1D[m] = arr1D[m+1];
}
四:生成任意的动态二维数组的源代码如下(基于vs2017):
从以上分析可以得到相应的源代码为:
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
//用一个二级指针定义一个二维数组
int **arr2D = NULL;
//一级指针指向一个一维数组
int *arr1D = NULL;
//定义一维数组元素个数,同时也是二维数组的元素个数
int len = 0;
//二维数组的行
int row;
//二维数组的列
int low;
//判断二维数组行和列是否正确
while (1)
{
cout << "请输入行:" << endl;
cin >> row;
cout << "请输入列:" << endl;
cin >> low;
if (row >= 1 && low >= 1)
{
len = low * row;
break;
}
else
{
cout << "请重新输入:" << endl;
cout << "请输入行:" << endl;
cin >> row;
cout << "请输入列:" << endl;
cin >> low;
}
}
//给一维数组开辟空间
arr1D = new int[len];
//初始化一维数组
for (int i = 0; i < len; i++)
{
arr1D[i] = i;
}
//给二级指针开辟列的空间
arr2D = new int*[row];
//标记随机数的值
int pos = 0;
//给二级指针中的一级指针开辟行的空间
for (int i = 0; i < row; i++)
{
arr2D[i] = new int[low];
}
//随机数种子
srand((unsigned int)time(NULL));
//给二维数组赋值
for (int i = 0; i < row; i++)
{
for (int j = 0; j < low; j++)
{
//获得随机数
pos = rand() % len;
//给二维数组赋值
arr2D[i][j] = arr1D[pos];
//一维数组的长度减1
len--;
//将一维数组中已经赋值给二维数组的元素删除(数组中删除元素的本质是数组元素的考贝)
for (int k = pos; k < len; k++)
{
//将原数组在k=pos后的元素向左移动一个位置,相当于覆盖原数组k=pos的元素达到删除的目的
arr1D[k] = arr1D[k + 1];
}
}
}
//打印二维数组
for (int i = 0; i < row; i++)
{
for (int j = 0; j < low; j++)
{
cout << arr2D[i][j] << "\t";
}
cout << endl;
}
//释放一维数组的空间
delete[] arr1D;
//二维数组的释放,先释放二级指针,再释放一级指针
for (int m = 0; m < row; m++)
{
delete[] arr2D[m];
}
delete[] arr2D;
system("pause");
return 0;
}
运行截图:
到此,我们就可以随意产生low行 row 列的随机不重复的二维数组了。欢迎各位看官在下面评论斧正。