Нерегулярные массивы. Выделение памяти. N-мерные нерегулярные массивы. Преимущества использования нерегулярных массивов. Примеры

Нерегулярные массивы. Выделение памяти. N-мерные нерегулярные массивы. Преимущества использования нерегулярных массивов. Примеры


Содержание


1. Что такое нерегулярные массивы? Характерные особенности нерегулярных массивов. Примеры объявления нерегулярных массивов

Нерегулярные массивы – это разновидность n-мерных (n>1) массивов, которые представлены как массивы одномерных массивов с разным количеством элементов.

В нерегулярном массиве размер одномерных массивов, которые соответствует последнему измерению, есть плавающим. Память для таких одномерных массивов выделяется разного объема.

При объявлении нерегулярного массива, по меньшей мере одно измерение не содержит конкретного значения (пустые квадратные скобки [ ]).

Например, ниже приведены примеры объявлений разных видов нерегулярных массивов

// объявление регулярных и нерегулярных массивов
int[][] A = new int[3][5]; // регулярный массив
int[][] B = new int[3][]; // нерегулярный двумерный массив
int[][][] C = new int[3][4][]; // нерегулярный трехмерный массив
int[][][] D = new int[3][][]; // нерегулярный трехмерный массив
// int[][][] E = new int[][][]; // ошибка, так нельзя объявлять массив

В вышеприведенном примере объявляется один регулярный (A) и три нерегулярных (B, C, D) массива.

2. Какое отличие между нерегулярными массивами и регулярными массивами? Пример

В регулярном массиве количество элементов в каждом измерении известно заранее. Это количество задается в момент выделения памяти для массива оператором new.

В нерегулярном массиве количество элементов как минимум в одном измерении неизвестно. Это количество может варьироваться в пределах этого измерения.

Например. Пусть объявлен регулярный массив A для которого выделена память

int[][] A = new int[3][5]; // регулярный массив, количество элементов = 3*5 = 15

В этом массиве количество элементов известно при выделении памяти оператором new.

В случае, если объявлен нерегулярный массив

int[][] B = new int[3][]; // нерегулярный массив, общее количество элементов неизвестно

то известно, что этот массив B содержит 3 одномерных массива. Количество элементов в любом из этих массивов неизвестно. Это есть признаком объявления нерегулярного массива. Чтобы сформировать эти 3 одномерных массива, можно написать, например, следующий код

// выделение памяти для массива B
for (int i=0; i<3; i++)
  B[i] = new int [i*2+1];

// заполнение массива B значениями
for (int i=0; i<3; i++)
  for (int j=0; j<B[i].length; j++)
    B[i][j] = i*3+j;

В вышеприведенном коде сначала выделяется память для любого из трех одномерных массивов: B[0], B[1], B[2]. Длина массива B[0] составляет 1. Длина массива B[1] равна 3. Длина массива B[2] равна 5. Чтобы определить длину массива, используется свойство length

int t;
t = B[0].length; // t = 1
t = B[1].length; // t = 3
t = B[2].length; // t = 5

После такого кода, количество элементов в нерегулярном массиве будет равно 1+3+5 = 9.

3. Какие преимущества использования нерегулярных массивов?

Использование нерегулярных массивов дает следующие преимущества:

  • в некоторых случаях существенно экономится память, когда в массиве есть большое количество неиспользованных элементов. В особенности это важно, если элементами нерегулярного массива являются объекты (экземпляры) классов, которые занимают много памяти;
  • установление разной контролируемой длины каждого одномерного массива в некоторых случаях может лучше отображать содержание решения поставленной задачи.



4. Могут ли нерегулярные массивы быть трехмерными, четырехмерными и больше?

Да, могут.

Например. Объявляется и используется трехмерный нерегулярный массив C.

int[][][] C = new int[3][4][]; // нерегулярный трехмерный массив

// создание нерегулярного массива C
// выделение памяти для массива C
for (int i=0; i<3; i++)
  for (int j=0; j<4; j++)
    C[i][j] = new int[(i+1)*(j+1)]; // память выделяется нерегулярно

// заполнение массива C значениями
for (int i=0; i<3; i++)
  for (int j=0; j<4; j++)
    for (int k=0; k<C[i][j].length; k++)
      C[i][j][k]=i+j+k;

int t;

// проверка
t = C[0][1][1]; // t = 2

5. Сколько измерений могут иметь нерегулярные массивы?

Нерегулярные массивы могут иметь два и более измерений. Наиболее распространенные это двумерные нерегулярные массивы. Однак, допускается объявление нерегулярных массивов с любым количеством измерений. Главное, чтобы первое (верхнее) измерение имело значение. Иначе, компилятор выдаст ошибку.

6. Пример объявления и использования двумерного нерегулярного массива типа int

В примере объявляется и используется нерегулярный двумерный массив с именем B. Массив содержит 3 одномерных массива размеры которых не совпадают.

// объявление нерегулярного массива B
int[][] B = new int[3][]; // нерегулярный двумерный массив

// выделение памяти для массива B
for (int i=0; i<3; i++)
  B[i] = new int [i*2+1];

// заполнение массива B значениями
for (int i=0; i<3; i++)
  for (int j=0; j<B[i].length; j++)
    B[i][j] = i*3+j;

int t;

// чтение значений элементов массива B
t = B[0].length; // t = 1
t = B[1].length; // t = 3
t = B[2].length; // t = 5
t = B[0][0]; // t = 0
t = B[1][0]; // t = 3
t = B[1][1]; // t = 4

7. Пример объявления и использования двумерного нерегулярного массива объектов (экземпляров) класса

Объявляется двумерный нерегулярный массив объектов класса WorkDay. Класс WorkDay содержит информацию об отработанных часах некоторым работником и тариф.

Также объявляется класс WorkYear, содержащий массив объектов WD типа WokrDay, который сгруппирован по месяцам года. Массив WD есть нерегулярным и содержит 12 одномерных массивов, каждый из которых соответствует месяцу года. Каждый одномерный массив имеет столько дней, сколько дней в соответствующем месяце года.

// класс, который описывает один рабочий день
class WorkDay {
  int hours; // количество отработанных часов
  double tariff; // расценка за час

  // конструктор класса
  WorkDay(int hours, double tariff) {
    this.hours = hours;
    this.tariff = tariff;
  }
}

// класс, который описывает рабочий год для некоторого работника
class WorkYear {
  // массив типа WorkDay, разбитый по месяцам года
  WorkDay[][] WD = new WorkDay[12][]; // нерегулярный массив объектов типа WorkDay

  // конструктор
  WorkYear() {
    // в конструкторе выделяется память для нерегулярного массива объектов
    WD[0] = new WorkDay[31]; // январь - 31 день
    WD[1] = new WorkDay[29]; // февраль - 29 (28) дней
    WD[2] = new WorkDay[31]; // март - 31 день
    WD[3] = new WorkDay[30]; // апрель - 30 дней
    WD[4] = new WorkDay[31]; // май
    WD[5] = new WorkDay[30]; // июнь
    WD[6] = new WorkDay[31]; // июль
    WD[7] = new WorkDay[31]; // август
    WD[8] = new WorkDay[30]; // сентябрь
    WD[9] = new WorkDay[31]; // октябрь
    WD[10] = new WorkDay[30]; // ноябрь
    WD[11] = new WorkDay[31]; // декабрь

    // обязательно нужно выделить память для любого объекта через конструктор
    for (int i=0; i<WD.length; i++)
      for (int j=0; j<WD[i].length; j++)
        WD[i][j] = new WorkDay(0, 0.0); // вызов конструктора
  }
}

Использование нерегулярного массива WD класса WorkYear может быть следующим

// использование нерегулярного массива WD класса WorkYear
WorkYear WY = new WorkYear();
int nDays; // количество дней в месяце

// проверка
nDays = WY.WD[5].length; // nDays = 30

// заполнение произвольного элемента массива WY
WY.WD[0][0].hours = 6; // 1 января
WY.WD[0][0].tariff = 200.00; // тариф = 200.00 денежных единиц
WY.WD[3][0].hours = 7; // 1 апреля
WY.WD[3][0].tariff = 130.00;

8. Пример объявления и использования трехмерного нерегулярного массива типа double

В примере объявляется класс DoubleArray, содержащий трехмерный нерегулярный массив D типа double. Выделение памяти и заполнение значениями элементов массива D реализуется в конструкторе класса.

// класс, содержащий трехмерный нерегулярный массив типа double
class DoubleArray {
  // объявление трехмерного нерегулярного массива типа double
  double[][][] D = new double[2][3][];

  // конструктор
  DoubleArray()
  {
    // выделение памяти для нерегулярного массива D[2][3][]
    D[0][0] = new double[5];
    D[0][1] = new double[6];
    D[0][2] = new double[3];
    D[1][0] = new double[4];
    D[1][1] = new double[5];
    D[1][2] = new double[7];

    // заполнение элементов массива произвольными значениями
    for (int i=0; i<D.length; i++)
      for (int j=0; j<D[i].length; j++)
        for (int k=0; k<D[i][j].length; k++)
          D[i][j][k] = i + j + k*0.25;
  }
}

Ниже демонстрируется использование класса DoubleArray

// использование нерегулярного массива D класса DoubleArray
DoubleArray da = new DoubleArray();
double x;

x = da.D[0][1][2]; // x = 1.5
x = da.D[1][0][3]; // x = 1.75
x = da.D[1][2][5]; // x = 4.25

9. Пример объявления и использования трехмерного массива целых чисел, в котором два измерения имеют переменное количество элементов

Объявляется и используется трехмерный массив D, в котором в двух измерениях не указывается количество элементов.

// в массиве D во 2-м и 3-м измерениях не указывается количество элементов
int[][][] D = new int[3][][]; // нерегулярный трехмерный массив

// int[][][] E = new int[][][]; // ошибка, так нельзя

// формирование массива D
// выделение произвольного размера памяти для 2-го измерения
for (int i=0; i<D.length; i++) // D.length = 3
  D[i] = new int[i+2][];

// выделение произвольного размера памяти для 3-го измерения
for (int i=0; i<D.length; i++)
  for (int j=0; j<D[i].length; j++)
    D[i][j] = new int [(i+2)*(j+1)];

// заполнение массива D значениями
for (int i=0; i<D.length; i++)
  for (int j=0; j<D[i].length; j++)
    for (int k=0; k<D[i][j].length; k++)
      D[i][j][k] = i+j*(k+2);

// можно и так
D[0][0][1] = 23;
D[1][2][2] = 230;

int t;

// использование массива D
t = D[0][1][2]; // t = 4
t = D.length; // t = 3
t = D[0].length; // t = 2
t = D[1].length; // t = 3
t = D[2].length; // t = 4
t = D[0][1].length; // t = 4
t = D[1][2].length; // t = 9

10. Пример объявления и использования трехмерного нерегулярного массива объектов (экземпляров) класса

Пусть задан некоторый класс с именем A. В классе реализована внутренняя переменная a целого типа и конструктор класса. Данный пример демонстрирует выделение памяти, заполнение значениями и использование трехмерного нерегулярного массива объектов класса A.

// некоторый класс A
class A {
  int a;

  // конструктор класса
  A(int a) {
    this.a = a;
  }
}

Нижеследующий код может служить примером для работы с трехмерным массивом объектов

// использование трехмерного нерегулярного массива объектов класса A
int n = 4;
A[][][] obj = new A[n][][]; // объявить объект obj как нерегулярный массив

// выделить память для нерегулярного массива элементов 2-го измерения
for (int i=0; i<obj.length; i++)
  obj[i] = new A[i+2][]; // некоторая формула

// выделить память для нерегулярного массива элементов 3-го измерения
for (int i=0; i<objA.length; i++)
  for (int j=0; j<objA[i].length; j++)
    objA[i][j] = new A[i+j+2];

// выделить память для объектов класса A
for (int i=0; i<objA.length; i++)
  for (int j=0; j<objA[i].length; j++)
    for (int k=0; k<objA[i][j].length; k++)
      obj[i][j][k] = new A(i+2*j+3*k); // вызов конструктора

// проверка
int t;
t = objA[0][1][2].a; // t = 8
t = objA[0][1][1].a; // t = 5


Связанные темы