Опубликован: 02.02.2011 | Уровень: для всех | Доступ: свободно
Лекция 15:

Двумерные массивы: задачи сортировок и перестановок в двумерных массивах

< Лекция 14 || Лекция 15: 12 || Лекция 16 >
Аннотация: В лекции рассматриваются типовые задачи на обработку двумерных массивов, приводятся примеры алгоритмизации задач сортировок и перестановок в двумерных массивах.

Цель лекции: изучить особенности применения алгоритмов сортировок и перестановок в двумерных массивах, научиться решать задачи сортировок и перестановок в двумерных массивах на языке C++.

В виде двумерных массивов удобно представлять объекты, элементы которых принадлежат одному типу и расположены в виде таблицы. Например, матрицы коэффициентов систем линейных уравнений, функциональные зависимости, линейные операторы, матрицу системы ограничений в задачах минимизации или максимизации, экспериментальные данные и т.д. При решении прикладных задач над элементами двумерных массивов бывает необходимо выполнить однотипные действия. Например, при решении систем линейных уравнений методом Гаусса требуется производить многократные перестановки строк. Для выполнения поиска в двумерных массивах данные бывает удобно упорядочить по определенному ключу, что также предполагает перестановки.

Однако, по сравнению с одномерными массивами, в матрицах перестановки и сортировки имеют немного другой смысл и алгоритм выполнения.

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

Пример 1. Сортировка в двумерном целочисленном массиве элементов k-той строки по невозрастанию.

void sort_dn(int k,int slb,  int m[max][max]) {  
  int i,j,buf; 
  for (i=0;i<slb;i++)
    for (j=slb-1;j>i;j--)
      if (m[k][j]>m[k][j-1]){
      //фиксированная строка с номером k 
           buf= m[k][j];
           m[k][j]= m[k][j-1];
           m[k][j-1]=buf; 
           } 
}

Для поиска максимальных (минимальных) элементов с целью их дальнейшего упорядочивания удобно выделять отдельно одномерный массив, в котором хранить не значения элементов, а номера столбцов или строк, в которых они располагаются. Например, чтобы найти минимальные элементы в каждом столбце массива n x m отдельно, удобно выделить одномерный массив min[m], в котором число элементов равно числу столбцов. Значениями элементов такого массива будут номера строк, в которых располагаются минимальные элементы каждого столбца. Если же минимальных элементов в столбце несколько, то будет найден первый (или последний) минимальный, что не скажется на значении.

Пример 2. Поиск номеров минимальных элементов в каждом столбце двумерного массива.

void minimum(int str,int slb, int m[max][max],int min[max_y]){
  int i,j; 
  for (j=0;j<slb;j++){//фиксируем номер столбца
    min[j]=0;
    for (i=1;i<str;i++)
    //пробег по столбцу, меняется номер строки
      if (m[i][j]<m[min[j]][j])  min[j]=i;  
  }
}

В данном примере min[max_y] – это массив, значениями которого будут номера строк, в которых располагается первый минимальный элемент столбца. Так для min[j] начальное значение инициализируется как 0, то есть предполагается, что минимальный элемент расположен в строке с номером 0. Обращение m[min[j]][j] понимается так: элемент массива m, расположенный в строке с номером min[j] и столбце с номером j. Но в строке min[j] для столбца j как раз и находится минимальный элемент.

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

Пример 3. Обмен значениями элементов диагоналей квадратной матрицы, расположенных в одной строке.

void obmen(int strslb, int m[max][max]) {  
  int i,buf,t; 
  for (i=0;i<strslb;i++){       
  //номера строки и столбца элемента главной диагонали равны
    buf= m[i][i];
    //t-номер столбца соответствующего элемента побочной диагонали
    t= abs(strslb-i-1);
    m[i][i]= m[i][t];
    m[i][t]=buf; 
  }
}

Пример 4. Дана квадратная матрица размера n x n, заполненная с клавиатуры целыми числами так, что в каждой строке и каждом столбце ровно по одному нулевому элементу. Переставьте строки матрицы так, чтобы нулевые элементы были расположены вдоль главной диагонали. Выведите массив на экран в виде таблицы дважды – до и после перестановки. Оформите генерацию, вывод массива и перестановку строк с помощью функций.

#include "stdafx.h"
#include <iostream>
using namespace std;
#define max 10

void gen (int k,int x[max][max]);
void out (int k,int x[max][max]);
void change (int k,int x[max][max]);

int _tmain(int argc, _TCHAR* argv[]) {
  int a[max][max];
  int n; 
  do {
    printf("\nВведите количество элементов массива n (n<=%d):",
            max);
    scanf ("%d",&n);
  }
  while (n>max);
  gen(n,a);
  out(n,a);
  change(n,a);
  out(n,a);
  system("pause");
  return 0;
}

void gen (int k,int x[max][max]){
  int i,j;
  for (i=0;i<k;i++){
     printf("\nВведите значения элементов %d-й строки 
             массива: \n",i); 
    for (j=0;j<k;j++){
      printf("x[%d][%d]= ",i,j);
      scanf("%d",&x[i][j]);
     }
   }  
}

void out (int k,int x[max][max]){
  int i,j;
  printf("\nВывод значений %d элементов массива в строку: \n",k); 
  for (i=0;i<k;i++) {
     for (j=0;j<k;j++)
       printf("\t%d",x[i][j]);
     printf("\n");
   }
}

void change (int k,int x[max][max]){
 int i,j,buf; 
 int zero[max]; //массив номеров столбцов нулевых элементов
 for (i=0;i<k;i++) //инициализация массива
    zero[i] = -1;
 for (i=0;i<k;i++) 
   for (j=0;j<k;j++)
   /*генерация массива номерами столбцов, в которых 
     расположены нулевые элементы*/
    if (x[i][j]==0) {
      zero[i]=j;
      j=k;
    }
  for (i=0;i<k;i++) 
   for (j=0;j<k;j++){
   /*обмен значениями элементов текущей строки с 
     соответствующей, чтобы нулевой элемент занял место на 
     главной диагонали*/
      buf=x[i][j];
      x[i][j]=x[zero[i]][j];
      x[zero[i]][j]=buf; 
   /*после перестановки строк изменяется номер столбца  
     нулевого элемента*/
      zero[zero[i]]=zero[i];
    }
}

В данном примере zero[max] – это массив, значениями которого будут номера столбцов, в которых располагается нулевой каждой строки (по условию задачи, такой элемент в каждом столбце и каждой строке единственный). Обращение x[zero[i]][j] понимается так: элемент массива x, расположенный в строке с номером zero[i] и столбце с номером j. Но для строки с номером i нулевой элемент располагается в столбце с номером zero[i]. Для каждого элемента главной диагонали индексы строки и столбца равны, поэтому нулевой элемент из столбца zero[i] должен быть перемещен в строку с аналогичным номером (вместе со всеми элементами этой же строки). Обращение zero[zero[i]] означает, что после перестановки строк с номерами i и zero[i] нулевой элемент строки zero[i] будет находиться в столбце с номером zero[zero[i]].

В языке С++ могут объявляться и использоваться в программах массивы, измерение которых больше двух. Такие массивы называют многомерными. Ограничения на число измерений массива зависит от реализации. Индексация многомерных массивов производится по каждому измерению в отдельности. Например, объявление трехмерного вещественного массива оформляется так:

float mass[max_x][max_y][max_z];

При объявлении многомерного массива формируется массив указателей на массивы, измерение которых на единицу меньше. Такое объявление рекурсивно сводится к массивам указателей на одномерные массивы.

Инициализация многомерных массивов во многом аналогична инициализации двумерных массивов и производится с учетом всех измерений. Обращение к элементам таких массивов возможна также через индексированное имя или с помощью адресной арифметики с указателями.

При обходе многомерных массивов в программах используются кратные циклы, каждый из которых пробегает по своему индексу. При организации обхода следует учитывать, что индекс внешнего цикла меняется медленнее остальных индексов кратных циклов.

Массивы слишком больших измерений неудобны в использовании, так как громоздки в объявлении и обращении, их индексация требует дополнительных затрат памяти, что увеличивает время выполнения программы.

Ключевые термины

Задачи перестановок в двумерных массивах – это тип задач, предполагающий обмен значениями элементов массива в зависимости от условия.

Задачи сортировок в двумерных массивах – это тип задач, предполагающий упорядочивание по указанному ключу одномерных массивов, из которых построен двумерный массив.

Многомерные массивы – это массивы с измерением больше единицы.

Краткие итоги

  1. Задачи обработки двумерных массивов имеют широкое прикладное значение.
  2. Задачи на использование массивов можно классифицировать в зависимости от вида обработки его элементов.
  3. Задачи перестановок предполагают перемещение элементов в массиве на заданные позиции. При этом сами значения элементов не изменяются.
  4. В задачах сортировок двумерных массивов упорядочиваются по указанному ключу одномерные массивы, из которых построены матрицы.
  5. При обходе двумерных массивов используют кратные циклы, каждый из которых пробегает по конкретному измерению.
  6. В С++ предусмотрено использование многомерных массивов.
  7. Массивы слишком больших измерений неудобны в использовании в программах.
< Лекция 14 || Лекция 15: 12 || Лекция 16 >
Денис Курбатов
Денис Курбатов
Владислав Нагорный
Владислав Нагорный

Подскажите, пожалуйста, планируете ли вы возобновление программ высшего образования? Если да, есть ли какие-то примерные сроки?

Спасибо!