Класс "Матрица"

Скачать (download)

Содержимое файла "matrix.h"

/*
** Класс "матрица"
** Слава Антонов (с) 2003
*/

//----------------------------------------------------------------------------

#ifndef MATRIX_H
#define MATRIX_H

#include 

  typedef long double tableitem;

// класс "строка вещественных чисел"
// по умолчанию все элементы - нулевые
  class CRow {
  protected:
    unsigned size;    // кол-во элементов
    tableitem *items; // массив элементов
  public:
  // конструктор по умолчанию
    CRow();
  // конструктор копирования
    CRow(const CRow& r);
  // конструктор с заданным размером
    CRow(unsigned uSize);
  // деструктор
    ~CRow();
  // обнуление всех элементов
    void zero_items();
  // кол-во элементов
    unsigned getSize() const { return size; }
  // изменение размера столбца, старые значения сохр, новые = 0
    CRow& setSize(unsigned uSize);
  // оператор [], индекс от нуля
    tableitem& operator [](unsigned uIndex);
    const tableitem& operator [](unsigned uIndex) const;
  // оператор вывода
    friend ostream& operator << (ostream& s, CRow& r);
  // оператор ввода
    friend istream& operator >> (istream& s, CRow& r);
  // оператор присваивания
    CRow& operator = (const CRow& r);
  };

  class CVector : public CRow {
    protected:
    public:
      CVector() : CRow () {};
      CVector(const CVector& v) : CRow(v) {};
      CVector(unsigned uSize) : CRow(uSize) {};

    // сумма векторов
      CVector operator +(const CVector &v) const;
      CVector operator -(const CVector &v) const;  
    // скалярное произведение векторов
      tableitem operator * (const CVector& v);
    // умножение вектора на скаляр
      friend CVector operator * (tableitem s, const CVector &v);
    // оператор присваивания
      CVector& operator = (const CRow& r);
  };

/* Класс "Таблица"
** Можно динамачески менять размеры.
** При этом старые значения сохраняются.
** Поддерживаются операторы: <<, >>, =
*/
  class CTable {
  protected:
 // массив строк
    CVector *items;
 // ширина и высота таблицы
    unsigned width;
    unsigned height;
  public:
    CTable();
    CTable(const CTable& t);
    CTable(unsigned uHeight, unsigned uWidth);
    ~CTable();
    unsigned getWidth() const { return width; }
    unsigned getHeight() const { return height; }
 // изменить размеры таблицы
    CTable& setSize(unsigned uHeight, unsigned uWidth);
  /*
  // поиск элемента с указанным значением в прямоугольнике с указанной лев. верней вершиной до конца таблицы
  // возвращаеются его координаты если он есть.
  // match - искать равный элемент или отличный от указанного
  // результат функции 0 - не найнен, не 0 - найден
  */
    int search(tableitem what, bool match, unsigned &uI, unsigned &uJ, unsigned starti = 0, unsigned startj = 0) const;

  // меняет два столбца местами
    CTable& swapcolumns(unsigned j1, unsigned j2);
  // меняет две строки местами
    CTable& swaprows(unsigned i1, unsigned i2);

 // оператор доступа [], индекс от нуля
    CVector& operator [](unsigned uIndex);
    const CVector& operator [](unsigned uIndex) const;
 // оператор вывода
    friend ostream& operator << (ostream& s, CTable& t);
 // оператор ввода. сработает только если таблица
 // имеет не нулевые размеры
    friend istream& operator >> (istream& s, CTable& t);
 // оператор присваивания
    CTable& operator = (const CTable& t);
  };

// класс "Матрица", наследник класса "Таблица"
  class CMatrix: public CTable {
  private:
  public:
  // вызывает конструктор базового класса
    CMatrix() : CTable() {};
    CMatrix(const CMatrix& m) : CTable(m) {};
    CMatrix(unsigned uHeight, unsigned uWidth) : CTable(uHeight, uWidth) {};
//    ~CMatrix() : ~CTable() {};
  // определитель матрицы
    tableitem determinant() const;
  // ранг матрицы. 0 - если ошибка  
    unsigned rang() const;
  // возврашает матрицу полученную из исходной вычеркиванием i-ой строки
  // и j-го столбца
    CMatrix minor (unsigned i, unsigned j) const;
  // транспонирование матрицы
    CMatrix& transpon();
  // сложение матриц
    CMatrix operator +(const CMatrix &m) const;
  // вычитание матриц
    CMatrix operator -(const CMatrix &m) const;
  // умножение матриц
    CMatrix operator * (const CMatrix &m) const;
  // обращение матрицы
    CMatrix operator ! () const;
  // умножение матрицы на вектор
    friend CVector operator * (const CMatrix &m, const CVector &v);
  // умножение матрицы на скаляр
    friend CMatrix operator * (const tableitem &scalar, const CMatrix &m);
  };

#endif

Содержимое файла "matrix.cpp"

#include "matrix.h"
#include 
#include 
#include 

//----------------------------------------------------------------------------

// конструктор по умолчанию
CRow::CRow() {
  size = 0;
  items = 0;
};

//----------------------------------------------------------------------------

// конструктор копирования
CRow::CRow(const CRow& r) {
  size = r.size;
  items = new tableitem[size];
  for (unsigned i = 0; i < size; i++)
    items[i] = r.items[i];
};

//----------------------------------------------------------------------------

// конструктор с заданным размером
CRow::CRow(unsigned uSize) {
  size = uSize;
  items = new tableitem[size];
  zero_items();
};

//----------------------------------------------------------------------------

// деструктор
CRow::~CRow() {
  if (size != 0) delete []items;
};

//----------------------------------------------------------------------------

// обнуление всех элементов
void CRow::zero_items() {
  for (unsigned i = 0; i < size; i++)
    items[i] = 0;
};

//----------------------------------------------------------------------------

// изменение размера, старые значения сохр, новые = 0
CRow& CRow::setSize(unsigned uSize) {
  if (uSize == size) return *this;
  tableitem *tmp = 0;
  if (uSize > 0) tmp = new tableitem[uSize];
  for (unsigned i = 0; i < uSize; i++)
    if (i < size) tmp[i] = items[i];
    else tmp[i] = 0;
  if (size != 0) delete []items;
  items = tmp;
  size = uSize;
  return *this;
};

//----------------------------------------------------------------------------

// оператор доступа к элементу
tableitem& CRow::operator [](unsigned uIndex) {
  return items[uIndex];
};

const tableitem& CRow::operator [](unsigned uIndex) const {
  return items[uIndex];
};

//----------------------------------------------------------------------------

// оператор вывода
ostream& operator << (ostream& s, CRow& r) {
  for (unsigned i = 0; i < r.size; i++) {
    s.width(10);
    s.right;
    s << r.items[i];
  }
  return s;
};

// оператор ввода
istream& operator >> (istream& s, CRow& r) {
  tableitem tmp;
  for (unsigned i = 0; i < r.size; i++) {
    cout << endl << "Enter item [" << i << "] = ";
    s >> tmp;
    r.items[i] = tmp;
    s.ignore(); 
  }
  return s;
};

//----------------------------------------------------------------------------

// оператор присваивания
CRow& CRow::operator = (const CRow& r) {
  setSize(r.size);
  for (unsigned x = 0; x < size; x++)
    items[x] = r.items[x];
  return *this;
};

/*
// Реализация методов Вектора
*/

// сумма векторов
CVector CVector::operator +(const CVector &v) const
{
  CVector res(*this);
  for (unsigned i = 0; i < res.size; i++)
    res[i] = res[i] + v[i];
  return res;
}

CVector CVector::operator -(const CVector &v) const
{
  CVector res(*this);
  for (unsigned i = 0; i < res.size; i++)
    res[i] = res[i] - v[i];
  return res;
}

// скалярное произведение векторов
tableitem CVector::operator * (const CVector& v) {
  tableitem res = 0;
  if (size != v.size) return 0;

  for (unsigned i = 0; i < size; i++)
    res += items[i] * v.items[i];
  return res;
};

// умножение вектора на скаляр
CVector operator * (tableitem s, const CVector &v) {
  CVector nv(v.size);
  for (unsigned i = 0; i < v.size; i++)
    nv[i] = v[i]*s;
  return nv;
};

// оператор присвоения
CVector& CVector::operator = (const CRow& r) {
  setSize(r.getSize());
  for (unsigned i = 0; i < size; i++)
    items[i] = r[i];
  return *this;
};

//----------------------------------------------------------------------------

// конструктор по умолчанию
CTable::CTable() {
  width = 0;
  height = 0;
  items = 0;
};

//----------------------------------------------------------------------------

// конструктор копирования
CTable::CTable(const CTable& t) {
  width = t.width;
  height = t.height;
  items = new CVector[height];
  for (unsigned x = 0; x < height; x++) {
    items[x].setSize(width);
    for (unsigned y = 0; y < width; y++)
      items[x][y] = t.items[x][y];
  }
};

//----------------------------------------------------------------------------

CTable::CTable(unsigned uHeight, unsigned uWidth) {
  width = uWidth;
  height = uHeight;
  items = new CVector[height];
  for (unsigned x = 0; x < height; x++)
    items[x].setSize(width);
};

//----------------------------------------------------------------------------

// деструктор
CTable::~CTable() {
  if (height != 0) delete []items;
};

//----------------------------------------------------------------------------

// изменить ширину таблицы
CTable& CTable::setSize(unsigned uHeight, unsigned uWidth) {
  if ((width == uWidth) && (height == uHeight)) return *this;
  CVector *tmp = 0;
// create table
  if (uHeight) tmp = new CVector[uHeight];
// copy old values
  for (unsigned x = 0; x < uHeight; x++) {
    tmp[x].setSize(uWidth);
    for (unsigned y = 0; y < uWidth; y++)
      if ((x < height) && (y < width)) tmp[x][y] = items[x][y];
      else tmp[x][y] = 0;
  }
  if (height != 0) delete []items;
  items = tmp;
  width = uWidth;
  height = uHeight;
  return *this;
};

//----------------------------------------------------------------------------

/*
// поиск элемента с указанным значением
// возвращаеются его координаты если он есть.
// match - искать равный элемент или отличный от указанного
// результат функции 0 - не найнен, не 0 - найден
*/
int CTable::search(tableitem what, bool match, unsigned &uI, unsigned &uJ, unsigned starti, unsigned startj) const {
  if ((!width) || (!height)) return 0;
  if ((starti >= height) || (startj >= width)) return 0;
  for (unsigned i = starti; i < height; i++)
    for (unsigned j = startj; j < width; j++)
      if (match == true) {
        if (items[i][i] == what) {
          uI = i;
          uJ = j;
          return 1;
        }
      }
      else
        if (items[i][j] != what) {
          uI = i;
          uJ = j;
          return 1;
        }
  return 0;
}; // CTable::search()

//----------------------------------------------------------------------------

// меняет два столбца местами
CTable& CTable::swapcolumns(unsigned x1, unsigned x2) {
  if ((x1 >= width) || (x2 >= width) || (x1 == x2)) return *this;
  tableitem tmp;
  for (unsigned x = 0; x < height; x++) {
    tmp = items[x][x1];
    items[x][x1] = items[x][x2];
    items[x][x2] = tmp;
  }
  return *this;
}; // swarcolumns()

//----------------------------------------------------------------------------

// меняет две строки местами
CTable& CTable::swaprows(unsigned i1, unsigned i2) {
  if ((i1 >= height) || (i2 >= height) || (i1 == i2)) return *this;
  CRow tmp = items[i1];
  items[i1] = items[i2];
  items[i2] = tmp;
  return *this;
}; // swaprows()


//----------------------------------------------------------------------------

// оператор доступа [], индекс от нуля
CVector& CTable::operator [](unsigned uIndex) {
  return items[uIndex];
};

const CVector& CTable::operator [](unsigned uIndex) const{
  return items[uIndex];
};

//----------------------------------------------------------------------------

// оператор вывода
ostream& operator << (ostream& s, CTable& t) {
  for (unsigned i = 0; i < t.height; i++) {
    for (unsigned j = 0; j < t.width; j++) {
      s.width(10);
      s.right;
      s << t.items[i][j];
    }
    s << endl;
  }
  return s;
};

//----------------------------------------------------------------------------

// оператор ввода. сработает только если таблица
// имеет не нулевые размеры
istream& operator >> (istream& s, CTable& t) {
  if ((t.width == 0) || (t.height == 0)) return s;
  for (unsigned i = 0; i < t.height; i++)
    for (unsigned j = 0; j < t.width; j++) {
      cout << endl << "Enter item[" << i << ", " << j << "] = ";
      s >> t.items[i][j];
    }
  if (s.peek() == '\n') s.ignore();
  return s;
};

//----------------------------------------------------------------------------

// оператор присваивания
CTable& CTable::operator = (const CTable& t) {
  setSize(t.width, t.height);
  for (unsigned i = 0; i < height; i++)
    items[i] = t.items[i];
//  for (unsigned i = 0; i < width; i++)
//    for (unsigned y = 0; y < height; y++)
//      items[x][y] = t.items[x][y];
  return *this;
};

/*
** Реализация методов класса "Матрица
*/

//----------------------------------------------------------------------------

// Вычисление определителя квадратной матрицы
tableitem CMatrix::determinant() const { 
/* TODO : Обработка ошибки */
  if (width != height) return 0;
  if (width == 0) return 0;

  CMatrix m = *this;
  if (width == 1) return m[0][0];

  if (width == 2)
    return (m[0][0] * m[1][1] - m[1][0] * m[0][1]);

// смена знака определителя. по умолчанию - нет
  bool sign = false;
// определитель
  tableitem det = 1;
  tableitem tmp;
  unsigned x, y;
// цикл по всей главной диагонали
  for(unsigned i = 0; i < height; i++) {
  // если элемент на диагонали равен 0, то ищем не нулевой элемент в матрице
    if (m[i][i] == 0) {
    // если все элементы нулевые, то опр. = 0
      if (!m.search(0, false, y, x, i, i)) return 0;
    // меняем i-ую строку с y-ой
      if (i != y) {
        m.swaprows(i, y);
        sign = !sign;
      }
    // меняем i-ый столбец с x-ым
      if (i != x) {
        m.swapcolumns(i, x);
        sign = !sign;
      }
    // таким образом, в m[i][i], теперь ненулевой элемент.
    }

  // выносим элемент m[i][i] за определитель
    det *= m[i][i];
    tmp = m[i][i];
    for (x = i; x < width; x++) {
      m[i][x] = m[i][x] / tmp;
    }
  // таким образом m[i][i] теперь равен 1
  // зануляем все элементы стоящие под (i, i)-ым,
  // при помощи вычитания с опр. коеффициентом
    for (y = i + 1; y < height; y++) {
      tmp = m[y][i];
      for (x = i; x < width; x++)
        m[y][x] -= (m[i][x]*tmp);
    }
  }
  if (sign) return det*(-1);
  return det;
}; // CMatrix::determinant()

//----------------------------------------------------------------------------
// вычисление ранга матрицы
unsigned CMatrix::rang() const {
  if (!width || !height) return 0;

  CMatrix m = *this;
  if (width == 1) return 1;

  tableitem tmp;
  unsigned i;
  unsigned x, y;
// выбираем минимум
  unsigned endi = (width > height)? height : width;
// цикл по всей главной диагонали
  for(i = 0; i < endi; i++) {
  // если элемент на диагонали равен 0, то ищем не нулевой элемент в матрице
    if (m[i][i] == 0) {
    // если все элементы нулевые, прерываем цикл
      if (!m.search(0, false, y, x, i, i)) break;
    // меняем i-ую строку с y-ой
      if (i != y) m.swaprows(i, y);
    // меняем i-ый столбец с x-ым
      if (i != x) m.swapcolumns(i, x);
    // таким образом, в m[i][i], теперь ненулевой элемент.
    }

  // выносим элемент m[i][i]
    tmp = m[i][i];
    for (x = i; x < width; x++) {
      m[i][x] = m[i][x] / tmp;
    }
  // таким образом m[i][i] теперь равен 1
  // зануляем все элементы стоящие под (i, i)-ым и справа от него,
  // при помощи вычитания с опр. коеффициентом
    for (y = i + 1; y < height; y++) {
      tmp = m[y][i];
      for (x = i; x < width; x++)
        m[y][x] -= (m[i][x]*tmp);
    }
    for (x = i + 1; x < width; x++) {
      tmp = m[i][x];
      for (y = i; y < height; y++)
        m[y][x] -= (m[y][i]*tmp);
    }
  }

// считаем сколько единичек на главной диагонали
  unsigned cnt = 0;
  for (i = 0; i < endi; i++)
    if (m[i][i] == 0) break;
    else cnt++;
  if (!cnt) cnt++;  
  return cnt;
}; // rang()

// возврашает матрицу полученную из исходной вычеркиванием i-ой строки
// и j-го столбца
CMatrix CMatrix::minor (unsigned i, unsigned j) const
{
  if ((i >= this->width) || (j >= this->height)) return *this;
  CMatrix M(this->height-1, this->width-1);
  if ((!M.width) || (!M.height)) return M;
  unsigned i1, j1;
  for (unsigned i2 = 0; i2 < M.height; i2++)
    for (unsigned j2 =0; j2 < M.width; j2++)
    {
      if (i2 < i) i1 = i2;
      else i1 = i2 + 1;
      if (j2 < j) j1 = j2;
      else j1 = j2 + 1;
      M[i2][j2] = this->operator[](i1)[j1];
    }
  return M;
}

// транспонирование матрицы
CMatrix& CMatrix::transpon() {
  if (!width || !height) return *this;
  CMatrix &m = *this;
  CMatrix m2(height, width);
  for (unsigned x = 0; x < width; x++)
    for (unsigned y = x + 1; y < height; y++)
      m2[y][x] = m[x][y];
  m = m2;
  return *this;
};

/*
** сложение матриц
*/
CMatrix CMatrix::operator +(const CMatrix &m) const
{
  CMatrix nm(m);
  if (!this->width || !this->height || !m.width || !m.height) return *this;
  if ((this->width != m.width) || (this->height != m.height)) return *this;
  nm.setSize(this->height, this->width);
  for (unsigned i = 0; i < this->height; i++)
    for (unsigned j = 0; j < this->width; j++)
      nm[i][j] = ((nm[i][j]) + (this->operator[](i)[j]));
  return nm;
}

// вычитание матриц
CMatrix CMatrix::operator -(const CMatrix &m) const
{
  CMatrix nm(m);
  if (!this->width || !this->height || !m.width || !m.height) return *this;
  if ((this->width != m.width) || (this->height != m.height)) return *this;
  nm.setSize(this->height, this->width);
  for (unsigned i = 0; i < this->height; i++)
    for (unsigned j = 0; j < this->width; j++)
      nm[i][j] = ((this->operator[](i)[j]) - (nm[i][j]));
  return nm;
}

// обращение матрицы
CMatrix CMatrix::operator ! () const
{
  CMatrix A(*this);
  if (!A.getWidth() || !A.getHeight()) return A;
  if (!A.determinant()) return A;
  CMatrix Inv(A.getHeight(), A.getHeight());
  tableitem tmp;
  unsigned i, j;
  unsigned x, y;
  for (i = 0; i < Inv.getHeight(); i++)
    Inv[i][i] = 1;

  for (unsigned i = 0; i < A.getHeight(); i++)
  {
    if (A[i][i] == 0) {
    // если все элементы нулевые, прерываем цикл
      if (!A.search(0, false, y, x, i, i)) break;
    // меняем i-ую строку с y-ой
      if (i != y)
      {
        A.swaprows(i, y);
        Inv.swaprows(i, y);
      }
    // меняем i-ый столбец с x-ым
      if (i != x)
      {
        A.swapcolumns(i, x);
        Inv.swapcolumns(i, x);
      }
    // таким образом, в A[i][i], теперь ненулевой элемент.
    }

  // выносим элемент A[i][i]
    tmp = A[i][i];
    for (x = 0; x < width; x++)
    {
      A[i][x] = A[i][x] / tmp;
      Inv[i][x] = Inv[i][x] / tmp;
    }

  // таким образом A[i][i] теперь равен 1
  // зануляем все элементы стоящие под и над (i, i)-ым
  // при помощи вычитания с опр. коеффициентом
    for (y = 0; y < height; y++)
    {
      if (y == i) continue;
      tmp = A[y][i];
      for (x = 0; x < width; x++)
      {
        A[y][x] -= (A[i][x]*tmp);
        Inv[y][x] -= (Inv[i][x]*tmp);
      }
    }
  }
  return Inv;
}

// умножение матриц
CMatrix CMatrix::operator * (const CMatrix &m) const {
  CMatrix nm;
  unsigned w, h;
  if (!this->width || !this->height || !m.width || !m.height) return nm;
  if (this->width != m.height) return nm;
  nm.setSize(this->height, m.width);
  h = nm.height;
  w = nm.width;
  tableitem item;
  for (unsigned i = 0; i < h; i++)
    for (unsigned j = 0; j < w; j++) {
      item = 0;
      for (unsigned k = 0; k < this->width; k++)
        item += this->operator[](i)[k] * m[k][j];
      nm[i][j] = item;
    }
  return nm;
};

// умножение матрицы на вектор
CVector operator * (const CMatrix &m, const CVector &v)
{
  CVector nv;
  if (!m.getWidth() || !m.getHeight() || (m.getWidth() != v.getSize()));
  unsigned w = m.getWidth();
  unsigned h = m.getHeight();
  nv.setSize(h);
  tableitem item;
  for (unsigned i = 0; i < h; i++) {
    item = 0;
    for (unsigned k = 0; k < w; k++)
      item += m[i][k]*v[k];
    nv[i] = item;
  }
  return nv;
};

// умножение матрицы на скаляр
CMatrix operator * (const tableitem &scalar, const CMatrix &m)
{
  CMatrix nm(m);
  for (unsigned i = 0; i < nm.height; i++)
    for (unsigned j = 0; j < nm.width; j++)
      nm[i][j] = scalar * nm[i][j];
  return nm;
}
Слава Антонов © 2002 — August 13, 2008
Индекс цитирования 197-577-902 ICQ-статус
Hosted by uCoz