Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Помогите написать код!


Автор: hello19 4.8.2011, 09:50
Хай! Тут такое дело... В матрице есть несколько нулевых строчек и нулевых столбцов. Надо их "вычеркнуть" из матрицы и вывести полученный результат. Вот например так:
Из такой вот матрицы:   
1 2 0 3
4 5 0 6
0 0 0 0 
7 8 0 9
Получить такую:
1 2 3
4 5 6
7 8 9
Что то не соображу как.. помогите с кодом.

Автор: bsa 4.8.2011, 10:30
а какие собственно проблемы? пишешь двойной цикл (с конца в начало), в нем проверяешь элементы каждой строки(столбца) на близость к нулю (ты же float/double используешь!). Если хоть один элемент не соответствует условию, то переходишь на следующую строку (столбец). Если все соответствуют, то строку(столбец) удаляешь.

Автор: hello19 4.8.2011, 10:36
Ну помогите с написанием то кода.. уже давно сижу.. чет не работает(

Добавлено через 13 минут и 36 секунд
Вот мой код:
Код

int main()
{
    int range = 5;

    // Allocate memory to matrix
    double **matrix = new double*[range];
    for (int i = 0; i < range; i++) 
    {
        matrix[i] = new double[range];
    }


    // reading from file
    ifstream ifs("aa.txt");
    double q;
    int i = 0;
    int j = 0;
    while ( ifs >> q )
    {
        matrix[i][j] = q;
        j++;
        if ( j % range == 0 ) { i++; j = 0;}
    }
    ifs.close();


    // delete nessesary colums and rows

    // счетчит количества нулевых строк/столбцов
    int k = 0;
    ofstream inf("inf.txt");
    while ( i < range )
    {
        while ( j < range )
        //for ( int j = 0; j < range; j ++ )
        {
            if ( (matrix[i][j]==0) && (i==j) )
            {
                k++;
                inf << i << " " << matrix[i][j] << endl;
                // Сдвигаем столбец
                for ( int t = i; t < range; t++ )
                {
                    for ( int w = 0; w < range; w++ )
                    {
                        matrix[t][w] = matrix[t][w+1];
                    }
                    if ( t == range-k ){return 0;}

                }
                // Сдвигаем строчку
                for ( int t = j; t < range; t++ )
                {
                    for ( int r = 0; r < range-k; r++)
                    {
                        matrix[t][j] = matrix[t+1][j];
                    }
                    if ( t == range - k ){return 0;}
                }
            }
            j++;
        }
        j = 0;
        i++;
    }
    inf.close();

    // output matrix 
    ofstream ofs("bb.txt");
    for (int i = 0; i < range-k; i ++)
    {
        for (int j = 0; j < range-k; j++)
        {
            ofs << matrix[i][j] << " ";
        } ofs << endl;
    }
}


пока что тестю вот на такой матрице
1 2 0 3 5
4 5 0 6 5
0 0 0 0 0
7 8 0 9 5
5 5 0 5 5

Автор: hello19 4.8.2011, 10:52
Косяк в том, что не заходит в ту часть хода, где как раз и удаляю строку и столбец. 
На самом деле ничего не удаляю.. просто переношу.

Автор: xvr 4.8.2011, 11:37
Вопрос на засыпку - что по твоему делает return 0; в твоей программе в строках 48 и 58?  smile 

Автор: hello19 4.8.2011, 11:39
Пордонте... это результат частых исправлений кода... не успел убрать

Добавлено через 1 минуту и 23 секунды
Код

int main()
{
        int range = 5;
 
        // Allocate 2 matrix
        double **matrix = new double*[range]();
        for (int i = 0; i < range; i++) 
        {
                matrix[i] = new double[range]();
        }
 
        // reading from file
        ifstream ifs("aa.txt");
        double q;
        int i = 0;
        int j = 0;
        while ( ifs >> q )
        {
                matrix[i][j] = q;
                j++;
                if ( j % range == 0 ) { i++; j = 0;}
        }
        ifs.close();
        // delete nessesary colums and rows
 
        // счетчик количества нулевых строк/столбцов
        int k = 0;
        ofstream inf("inf.txt");
 
        // Тут я просто хочу удалить из массива нулевую строчку\столбец.
        for ( int i = 0; i < range; i++ )
        {
                if ( matrix[i][i] == 0 )
                {
                        inf << i << endl;
                        k++;
                        delete matrix[i];
                }
        }
        inf.close();
 
        // output matrix 
        ofstream ofs("bb.txt");
        for (int i = 0; i < range-k; i ++)
        {
                for (int j = 0; j < range-k; j++)
                {
                        ofs << matrix[i][j] << " ";
                } ofs << endl;
        }
        for ( int i =0; i < range-k; i++)
        delete[] matrix[i];
        delete[] matrix;
 

Я хочу просто удалять из матрицы необходимую строчку и столбец... По ходу - косяк в коде.

Автор: xvr 4.8.2011, 11:56
Цитата(hello19 @  4.8.2011,  11:39 Найти цитируемый пост)
        for ( int i = 0; i < range; i++ )
        {
                if ( matrix[i][i] == 0 )

Тут вы пробегаетесь по диагонали матрицы, а вовсе не по строкам/столбцам

Цитата(hello19 @  4.8.2011,  11:39 Найти цитируемый пост)
                       delete matrix[i];

Это тоже строку/столбец не удалит - только освободит память, где она лежала. Но все указатели (и место в массиве под нее) останется, в результате получим слом на попытке прочесть оттуда (если повезет  smile )

Совет - заведите битовые шкалы ненулевых строк/столбцов (до размера матрицы 32х32 будет достаточно 2х int'ов) и разметьте в них все ненулевые элементы. Физически удалять строки/столбцы из матрицы не надо, достаточно при выводе результата пропустить (не выводить) нулевые строки/столбцы

Автор: hello19 4.8.2011, 12:19
Вообщем, если я встречаю нулевой элемент на диагонали, то удаляю строчку и столбец его содержащие... Вот за этим то и нужны эти строчки

Добавлено через 7 минут и 57 секунд
Вообщем, если я встречаю нулевой элемент на диагонали, то удаляю строчку и столбец его содержащие... Вот за этим то и нужны эти строчки
 

Автор: hello19 4.8.2011, 12:50
Кстати, знаю, что не удалит. Но при выводе матрицы можно вот так писать:
Код

        for (int i = 0; i < range-k; i ++)
        {
                if ( matrix[i][i]!=NULL)
                {
                        for (int j = 0; j < range-k; j++)
                        {
                                ofs << matrix[i][j] << " ";
                        } ofs << endl;
                }
        }

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

Автор: borisbn 4.8.2011, 13:11
Код

#include <vector>
#include <iostream>

const int range = 5;

int main(int argc, char *argv[])
{
    std::vector< std::vector< double > > matrix( range, std::vector< double >( range ) );
    matrix[0][0]=1; matrix[0][1]=2; matrix[0][2]=0; matrix[0][3]=3; matrix[0][4]=5;
    matrix[1][0]=4; matrix[1][1]=5; matrix[1][2]=0; matrix[1][3]=6; matrix[1][4]=5;
    matrix[2][0]=0; matrix[2][1]=0; matrix[2][2]=0; matrix[2][3]=0; matrix[2][4]=0;
    matrix[3][0]=7; matrix[3][1]=8; matrix[3][2]=0; matrix[3][3]=9; matrix[3][4]=5;
    matrix[4][0]=5; matrix[4][1]=5; matrix[4][2]=0; matrix[4][3]=5; matrix[4][4]=5;

    for ( int i = 0; i < range; i++ ) {
        for ( int j = 0; j < range; j++ )
            std::cout << matrix[ i ][ j ] << "  ";
        std::cout << std::endl;
    }

    // сначала по строкам
    for ( int i = 0; i < matrix.size(); ) {
        bool allZeros = true;
        for ( int j = 0; j < range; j++ ) {
            if ( matrix[ i ][ j ] != 0 ) { // лучше переделать на fabs( matrix[ i ][ j ] ) > epsilon
                allZeros = false;
                break;
            }
        }
        if ( allZeros ) {
            matrix.erase( matrix.begin() + i );
        }
        else
            i++;
    }
    
    if ( matrix.empty() )
    {
        std::cout << "The whole matrix is zero" << std::endl;
        return 1;
    }

    // теперь по столбцам
    for ( int j = 0; j < matrix[ 0 ].size(); ) {
        bool allZeros = true;
        for ( int i = 0; i < matrix.size(); i++ ) {
            if ( matrix[ i ][ j ] != 0 ) { // лучше переделать на fabs( matrix[ i ][ j ] ) > epsilon
                allZeros = false;
                break;
            }
        }
        if ( allZeros ) {
            for ( int i = 0; i < matrix.size(); i++ ) {
                matrix[ i ].erase( matrix[ i ].begin() + j );
            }
        }
        else
            j++;
    }

    std::cout << "--------------------" << std::endl;

    for ( int i = 0; i < matrix.size(); i++ ) {
        for ( int j = 0; j < matrix[ i ].size(); j++ )
            std::cout << matrix[ i ][ j ] << "  ";
        std::cout << std::endl;
    }
}

http://liveworkspace.org/code/c1ab7b319267a4b8d0d4b78dce411ead

Автор: hello19 4.8.2011, 13:16
Отличный код!
Вот только сейчас переделывать буду. Просто мне надо работать с матрицей порядка 4000. По этому вектор не годиться... Сгодиться динамический массив. А так все супер!
А как удалить строчку из двумерного динамического массива грамотно?

Автор: bsa 4.8.2011, 13:25
Цитата(hello19 @  4.8.2011,  13:16 Найти цитируемый пост)
По этому вектор не годиться...

почему?!?  smile 
От обычного динамического массива в релизной сборке он не отличается (разве что вместо одного указателя на массив хранятся три)!

Автор: hello19 4.8.2011, 13:27
Стека не хватит, чтобы считаться матрицу даблов порядка 4000... это же 4000*4000 даблов...

Автор: borisbn 4.8.2011, 13:32
Цитата(hello19 @  4.8.2011,  13:27 Найти цитируемый пост)
Стека не хватит

читай внимательно !
Цитата(bsa @  4.8.2011,  13:25 Найти цитируемый пост)
От обычного динамического массива в релизной сборке он не отличается

вектор (вернее его содержимое) создаётся не на стеке, а в динамической памяти - куче.

Автор: W4FhLF 4.8.2011, 13:41
При работе с вектором векторов в студии я как-то наблюдал очень много лишних копирований. Так что тут спорно. 

Автор: bsa 4.8.2011, 13:46
Цитата(W4FhLF @  4.8.2011,  13:41 Найти цитируемый пост)
Так что тут спорно.  

для создания матрицы достаточно просто вектора. Если очень хочется, то можно попробовать дек векторов...

Автор: W4FhLF 4.8.2011, 13:49
И адресовать двумерные индексы через одномерные? Тогда можно. У меня в классе так и сделано. Просто гораздо удобнее оперировать двойными индексами.  

Автор: borisbn 4.8.2011, 14:00
W4FhLF, можно хранить указатель на вектор
Код

std::vector< std::vector< double> * > m;
*(m[ i ])[ j ]

выглядит не так красиво, но, действительно, копирований не будет.
Нужно ещё не забыть выделить память в начале и при erase'е - удалить
Код

    std::vector< std::vector< double > * > matrix( range );
    for ( int i = 0; i < range; i++ )
        matrix[ i ] = new std::vector< double >( range );
    *(matrix[0])[0]=1; *(matrix[0])[1]=2; *(matrix[0])[2]=0; *(matrix[0])[3]=3; *(matrix[0])[4]=5;
    .....
    if ( allZeros ) {
        delete matrix[ i ];
        matrix.erase( matrix.begin() + i );
    }

Автор: Silent 4.8.2011, 14:39
Раз матрица "большая", 4000х4000, то не надо выполнять лишних операций - аж два раза бегать по ней. Заведите себе два массивчика, посчитайте количество нулевых элементов в строке-столбце, и если значение равно N, то все понятно - выводить не стоит. Иллюстрирующий код:
Код

short index1[N], index2[N];    //indexX[i] <= 4000

for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++)
    {
        index1[i] += (matrix[i][j] == 0);    //помним, что сравнивать double надо не так
        index2[j] += (matrix[i][j] == 0);
    }


результат: плюс 16000 байт, минус N^2 операций, время выполнения этого участка наполовину уменьшается.

P.S. Кстати, рекомендую не применять двойную индексацию, и не применять динамические массивы. Хотя я, конечно, не знаю специфику задачи.

Автор: W4FhLF 4.8.2011, 14:48
borisbn, тогда обычный двумерный массив лучше. Кода столько же, а выглядит красивее. 

Автор: borisbn 4.8.2011, 14:55
Можно завернуть всё это безобразие в класс, использовать в нём простой вектор и переопределить оператор []
Код

class Vector2D
{
public:
    Vector2D( int range )
        : m_range( range )
    {
        m_matrix.resize( m_range * m_range );
    }
private:
    double & operator[]( int row ) { return m_matrix[ row * m_range ]; }
};

придётся подолбаться с ф-цией удаления строки и столбца (хотя тоже ничего военного... )

Автор: W4FhLF 4.8.2011, 15:02
У меня в классе матриц сделана перегрузка оператора () и тогда можно спокойно передавать двойные индексы без копирований:

Код

    inline const T& operator()(int row, int col) const
    {
#ifdef _DEBUG
        if(row >= m_rows || col >= m_cols)
            throw std::out_of_range("You've tried to access element which is out of range.");
#endif
        return m_data[col + row * m_cols];
    }

Автор: hello19 5.8.2011, 10:56
Нароод! помогиет!! 
Надо считать столбец свободных членов системы.
Решил просто проверить как работает. Считываю, записываю в массив, вывожу. Вот код:
Код

        int range;
    cin >> range;
    // Colum of free members
    double *free = new double[range];
    ifstream ifsf("B.txt");
    double q;
    int i = 0;
    int j = 0;
    while ( ifsf >> free[i] )
    {
        i++;
    }
    ifsf.close();
    ofstream ofs("B-0.txt");
    for ( int i = 0; i < range; i++ )
    {
        ofs << free[i] << endl;
    }
    ofs.close();

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)