Обход 2х-мерного массива по спирали
От: Аноним  
Дата: 13.09.02 07:15
Оценка:
Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?
Re: Обход 2х-мерного массива по спирали
От: Хитрик Денис Россия RSDN
Дата: 13.09.02 07:36
Оценка:
Здравствуйте Аноним, Вы писали:

А>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


Приведи здесь свой код. Напомни, что тебя в нём не устраивает.

Не забудь воспользоваться тегами форматирования (они появятся внизу, когда будешь писать сообщение) и лучше зарегистрироваться -- приятнее разговаривать с кем-то конкретно, а не с безликим Анонимом. К нам даже заходят люди с совершенно простыми вопросами под своими именами, и им дают подробные ответы, не глядя на уровень вопроса. Так что не бойся показаться начинающим

Удачи!
Правила нашего с вами форума.
Как правильно задавать вопросы. © 2001 by Eric S. Raymond; перевод: © 2002 Валерий Кравчук.
Re: Обход 2х-мерного массива по спирали
От: dad  
Дата: 13.09.02 08:15
Оценка:
Здравствуйте Аноним, Вы писали:

А>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


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

так же можно на чистой математике представить массив как линейный, использовать одну переменную для указания текущего индекса..
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[2]: Обход 2х-мерного массива по спирали
От: Alexander Kotelovich Латвия  
Дата: 13.09.02 08:49
Оценка:
Здравствуйте dad, Вы писали:

dad>Здравствуйте Аноним, Вы писали:


А>>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


dad>какой структурой масив задан? статический или динамический?

dad>первое ччто приходит в голову — нужно знать размерность массива, и индексы его центра..
dad>в цикле пока х и у не равны одновременно сентральной точке хранить дополнительное состояние — направление движения (право, вниз, влево, вверх) в зависимости от этих стостояний
dad>изменять значения текущего х и у..
dad>Так же можно разворячивать рекусрсивоно массив..

dad>так же можно на чистой математике представить массив как линейный, использовать одну переменную для указания текущего индекса..


Это я, бывший Аноним.

Размерность массива задается в пределах 1 < M < 10, 1 < N < 10. После чего требуется вывести спираль. Про статику и динамику в задании не слова, значит можно выбирать.

---+---+---+
|1 | 2 | 3 |
---+---+---+
|6 | 5 | 4 |
---+---+---+

примерно в таком виде.

Я примерно и начал так реализовывать, потом закрались мысли о полярных координатах, геом. формулах сприрали, периодичности знаков итд.
Re[3]: Обход 2х-мерного массива по спирали
От: Holms США  
Дата: 13.09.02 12:57
Оценка:
Здравствуйте Alexander Kotelovich, Вы писали:


AK>Я примерно и начал так реализовывать, потом закрались мысли о полярных координатах, геом. формулах сприрали, периодичности знаков итд.


Вот самый простой вариант ИМХО для начала чтоб что-то было


// spirali.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <conio.h>

const MAX_COLS = 10;
const MAX_ROWS = 10;

void    create_and_fill_array(int    ***array, int cols, int rows);
void    display_array(int **array, int cols, int rows);
void    parse_and_display_array(int **array, int cols, int rows);

int main(int argc, char* argv[])
{
    int        **ptr;
    int        cols, rows;
    std::cout << "Input the number on columns (< 10): "; 
    std::cin >> cols;
    if (cols > MAX_COLS) {
        std::cout << "Error. To big number.";
        return 0;
    }

    std::cout << "Input the number of rows (< 10): ";
    std::cin >> rows;
    if (rows > MAX_ROWS) {
        std::cout << "Error. To big number.";
        return 0;
    }
    
    create_and_fill_array ( &ptr, cols, rows );
    std::cout << "A random created array\n\n";
    display_array ( ptr, cols, rows );
    std::cout << "\n\nThe created vector\n\n";
    parse_and_display_array ( ptr, cols, rows );

    if(ptr){
        for(int i = 0; i < rows; i++)
            delete [] ptr[i];
        delete [] ptr;
    }

    std::cout << "\nPress any key...";
    getch();
    return 0;
}
//---------------------------------------------------------------------
void    create_and_fill_array(int    ***array, int cols, int rows)
{
    *array = new int*[ rows ];
    if (NULL == *array) {
        return ;
    }
    srand( time(NULL) );
    for(int i = 0; i < rows; ++i){
        (*array)[ i ] = new int[ cols ];
        for(int j = 0; j < cols; j++)
            (*array)[ i ][ j ] = rand() % 100;
    }
}
//---------------------------------------------------------------------
void    display_array(int **array, int cols, int rows)
{
    if (NULL == array) {
        return;
    }
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < cols; j++)
            std::cout << array[i][j] << '\t';
        std::cout << '\n';
    }
}
//---------------------------------------------------------------------
bool    is_done(bool    *ptr, int cols, int rows)
{
    for(int i = 0; i < rows; i++)
        for(int j = 0; j < cols; j++)
            if (!ptr[i * cols + j]) {
                return false;
            }
    return true;
}
//---------------------------------------------------------------------
void    parse_and_display_array(int **array, int cols, int rows)
{
    bool    *tmp = new bool[ cols * rows ];
    memset( tmp, 0, cols * rows );
    static short dx[] = { 1, 0, -1,  0 };
    static short dy[] = { 0, 1,  0, -1 };

    int startX(0), startY(0), iDir(0);
    int nextX, nextY;
    while (!is_done (tmp, cols, rows)) {

        std::cout << array[startY][startX] << ",";
        std::cout.flush ();
        tmp[startY * cols + startX] = 1;

        nextX = startX + dx[iDir];
        nextY = startY + dy[iDir];
        
        if (nextX < 0 || nextX >= cols
            ||
            nextY < 0 || nextY >= rows
            || 
            tmp[nextY * cols + nextX]) {
            iDir++;
            if (iDir > 3) {
                iDir = 0;
            }
            nextX = startX + dx[iDir];
            nextY = startY + dy[iDir];
        }
        startX = nextX;
        startY = nextY;
    }
    delete [] tmp;
}
//---------------------------------------------------------------------
The life is relative and reversible.
Re: Обход 2х-мерного массива по спирали
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.09.02 15:37
Оценка: 27 (3)
Здравствуйте Аноним, Вы писали:

А>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?

Гм. Не знаю, в чем именно проблема, я бы решал так:
Начнем с "середины" массива, обозначив ее буквой v (пусть она уже изветстна). Нарисуем путь обхода:
+---
|+-+
||v|
|++|
+--+
Итак, видно, что мы идем так:
1 вниз, 1 влево
2 вверх, 2 вправо
3 вниз, 3 влево...
Ага, вырисовывается примерно такой псевдокод:

int l=1;
while(1)
{
  int i;
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    y+=1;  //идем вниз
  }
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    x-=1;  //идем влево
  }
  l+=1; // увеличили шаг...
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    y-=1;  //идем вверх
  }
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    x+=1;  //идем вправо
  }
  l+=1;//  опять увеличиваем шаг...
}


Четыре цикла, однако, составляют две очень похожие пары. Свернем их:
int l=1;
d=1;
while(1)
{
  int i; // старые компиляторы не дадут нам повторно декларировать i во втором цикле...
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    y+=d;  //идем либо вверх, либо вниз...
  }
  for(i=0; i<l; i++) 
  {
    cout<< array[x][y];
    x-=d;  //идем либо влево, либо вправо...
  }
  l+=1; // увеличили шаг...
  d= -d; // инвертировали направление...
}

можно еще обобщить понятие движения. Сделаем каждый проход по стороне спирали в едином цикле:
typedef enum {down, left, up, right} direction;
direction dir = down;
struct {
 int dx; 
 int dy;
 int l
} step_struct;
const step_struct turn_desc[] = {{0, 1, 1}, {-1, 0, 0}, {0, -1, 1}, {1, 0, 0}};

step_struct step = turn_desc[dir];
void move(const step_struct &step, int &x, int &y)
{
  x+=step.dx;
  y+=step.dy;
}
void turn(step_struct &step, direction &dir)
{
  dir= (dir+1)%4;
  step.dx = turn_desc[dir].dx;
  step.dy = turn_desc[dir].dy;
  step.l += turn_desc[dir].l;
}

while(1)
{
  for(int i=0; i<step.l; i++) 
  {
    cout<< array[x][y];
    move(step, x, y);  //идем в нужную сторону
  }
  turn(step, dir); // поворачиваем
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Обход 2х-мерного массива по спирали
От: Alexander Kotelovich Латвия  
Дата: 14.09.02 14:28
Оценка:
Здравствуйте Аноним, Вы писали:

А>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


Спасибо за советы, переписал код, сейчас все гораздо лучше
Re: В один цикл
От: Pushkin Россия www.linkbit.com
Дата: 18.10.02 05:20
Оценка: 6 (1)
Здравствуйте Аноним, Вы писали:

А>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


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

int array[N][N];
for(int x=N/2, y=N/2;
    x>=0 && y>=0 && x<N && y<N;
    x+y<N/2*2? (x<y? y--:x++):(x>y? y++:x--))
{
    //do what you want with array[x][y]
}
Re[2]: Типа, круто!
От: potap  
Дата: 24.10.02 10:07
Оценка:
Здравствуйте Pushkin, Вы писали:

P>Здравствуйте Аноним, Вы писали:


А>>Начал реализовывать, однако получается довольно громоздкий код с 3мя циклами, существует ли более изящное решение?


P>В верхнем квадранте надо идти вправо, в правом вниз, в нижнем влево, в левом вверх.

P>Осталось внимательно посмотреть на границы и написать так, чтобы годилось и для чётных и для нечётных размерностей.

P>
P>int array[N][N];
P>for(int x=N/2, y=N/2;
P>    x>=0 && y>=0 && x<N && y<N;
P>    x+y<N/2*2? (x<y? y--:x++):(x>y? y++:x--))
P>{
P>    //do what you want with array[x][y]
P>}
P>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.