2 семестр / Условие. Шаблоны классов
Определить столбец двумерного массива A с максимальной суммой элементов и, если его номер больше заданного, сформировать массив из столбцов исходного массива до найденного столбца, иначе сформировать массив из элементов заданного столбца.
Если двумерный массив A, в котором количество строк совпадает с количеством столбцов, является треугольным (элементы выше главной диагонали равны нулю), вычислить среднее арифметическое его элементов, иначе определить, сколько элементов, лежащих выше главной диагонали, отличны от нуля.
Если k-й столбец двумерного массива A имеет минимальную сумму элементов, определить сумму элементов столбцов до k-го, иначе сумму элементов столбцов после k-го.
Если двумерный массив A из целых чисел, в котором количество строк совпадает с количеством столбцов, симметричен относительно главной диагонали, обнулить все элементы, лежащие выше главной диагонали, и определить сумму четных чисел, лежащих ниже главной диагонали.
Переставить в каждом столбце двумерного массива A все отрицательные элементы в конец столбца. Вывести часть полученного массива, состоящую из первых строк, не имеющих отрицательных элементов.
Двумерный массив A представляет координаты точек на плоскости. Если все точки попадают в круг с радиусом R и центром в начале координат, определить их среднюю абсциссу и ординату, иначе вывести номера точек, не попавших в заданный круг.
Если столбцы двумерного массива A расположены в порядке возрастания числа нулевых элементов в них, то подсчитать число нулевых элементов во всем массиве, иначе определить столбец с максимальным количеством нулей.
Если максимальный элемент двумерного массива A находится выше главной диагонали, транспонировать массив, иначе определить сумму элементов строки и столбца с номерами, равными индексам максимального элемента. Считаем, что максимальный элемент единственный.
Для двумерного массива A, в котором количество строк совпадает с количеством столбцов, увеличить все элементы строки с минимальной суммой элементов на среднее арифметическое элементов массива, лежащих выше главной диагонали.
Изменить двумерный массив A так, чтобы на первом месте стояла строка с максимальной, а на последнем месте строка с минимальной суммой элементов, сохранив все элементы исходного массива.
Если все заданные двумерным массивом A точки плоскости принадлежат первому квадранту, определить координаты точки, наиболее удаленной от начала координат, иначе вывести координаты точек, не попавших в первый квадрант.
Найти максимальный среди отрицательных элементов двумерного массива A и минимальный среди положительных. Если они отличаются по модулю меньше, чем на заданную величину, заменить все отрицательные элементы исходного массива их модулями.
Исходный двумерный массив представляет собой экзаменационные оценки группы по четырем предметам. Определить, попадает ли группа на конкурс лучших групп. Условия конкурса: средний балл группы выше 4, отсутствие неуспевающих, число студентов, не имеющих троек, больше половины всех студентов группы.
Подсчитать, как изменится среднее арифметическое элементов двумерного массива A, если во всех столбцах с номерами, большими, чем номер столбца с максимальным количеством отрицательных элементов, заменить все отрицательные элементы их модулями.
В двумерном массиве A поставить на первое место столбец с наименьшим количеством нулевых элементов, переставив все нули в конец этого столбца. Измененный массив должен содержать все элементы исходного.
В двумерном массиве A определить столбец, в котором все элементы расположены в порядке возрастания их значений. Если такого столбца нет, поменять порядок следования столбцов на противоположный.
Если в двумерном массиве A номер столбца с максимальной суммой элементов совпадает с номером строки с максимальной суммой элементов, определить сумму найденных элементов строки и столбца, иначе вывести номера найденных строки и столбца с максимальными суммами.
Если в первом столбце двумерного массива A все элементы по модулю больше заданной величины, разделить столбец с максимальным средним арифметическим элементов на соответствующие элементы первого столбца.
В каждом столбце двумерного массива A поставить на первое место максимальный по модулю элемент столбца, определив после этого среднее арифметическое элементов первой строки. Измененный двумерный массив должен содержать все элементы исходного.
Из двумерного массива A исключить столбец с максимальным числом нулевых элементов, сохранив все остальные элементы в том же порядке.
Для двумерного массива A из m строк и n столбцов сформировать одномерный массив B из m элементов. Каждый элемент Bi получает значение 0, если в i–ой строке массива A есть хотя бы один нулевой элемент, и значение 1 в противном случае. Для проверки наличия нулевых элементов в произвольной строке двумерного массива использовать подпрограмму.
Для двумерного массива A из m строк и n столбцов сформировать одномерный массив B из m элементов. Каждый элемент Bi получает значение, равное номеру максимального элемента (считаем, что он единственный) в i–й строке массива A. Для поиска номера максимального элемента в произвольной строке двумерного массива использовать подпрограмму.
Класс двумерной точки как шаблон в си
Здесь, на rsdn много раз обсуждались многомерные массивы (представлять как одномерные и проч.), но я среди обсуждений не нашёл именно того, что мне нужно.
Необходимо сделать объект — оболочку для массивов, для удобства работы с массивами. (Проблема стара как мир )
Т.е. обычным на С++ выглядит следующее:
< //Размерность первая const unsigned int s1 = 4; //Размерность вторая const unsigned int s2 = 8; //Временный массив для передачи данных функции int **arr = new int*[s1]; for(unsigned int i=0; inew int[s2]; //Заполняем массив for(unsigned int i=0; ifor(unsigned int j=0; j; //Вызываем некий метод некого объекта(это всё не важно, главное что ему //требуется указатель на указатель, являющийся массивом целых чисел) //прототипа навроде такого: setAD2(int** a, unsgined int size1, unsigned int size2) fv.setAD2(arr, s1, s2); //Метод забрал часть данных из двухмерного массива в своё внутренее хранилище, //о котором мы ничего не знаем и знать не хотим, массив нам больше не нужен //Освобождаем память for(unsigned int i=0; idelete[] arr[i]; delete[] arr; >
Утомляет всё это писать, хочется написать выделение и освобождение памяти раз и навсегда ( для всех массивов), чтобы можно было так:
< //Объявили массив и выделили память Arrayint> a(10); //Заполняем массив for(unsigned int i=0; i; //Вызвали функцию требующу указатель на инт, являющийся массивом и размер массива funcAr(a.getPoint(), a.size()); //Деструктор вызовется автоматически и //беспокоится о не освобождении памяти не нужно >
Это легко реализовать с помощью вот такого шаблона (привожу очень упрощенный вид):
template typename type> class A < private: type *arr; public: A() : arr(0) <>; A(int x) new type[x];>; type& opertor [] (int index) return arr[index];>; >;
Однако в таком случае для n-мерного массива (в примере ниже n=2) потребуется опять таки выделять память для каждого измерения:
< Aint> > ob1(10); //Получается память будет выделена только под одно измерение, как выделить под другое? a[3][8] = 5; //ошибка, обращаемся к памяти по "левому" адресу //Возможно сделать некий метод класса А под названием getMem, выделяющий память и вызывать его так: for(unsigned int i=0; i a[3][8] = 5; //всё отлично, память выделена assert(a[3][8] == 5); >
Решение рабочее, но не красивое — уж лучше вообще без объектов, просто int** и ему выделять память.
Тогда пришла идея сделать шаблон с параметром, вот такой:
template typename type, unsigned int size> class A < private: type *arr; public: A() : new type[size];>; type& opertor [] (int index) return arr[index];>; >;
Тогда код (1)
< Aint, 10>, 10> ob1; a[3][8] = 5; //всё отлично, память выделена >
. работает. Но не более.
Дальше начинаются извращения, например чтобы присваивать (кажется логичным массиву из 10 целочисленных элементов присвоить массив из 9 целочисленных элементов, просто скопировав 9 значений) надо делать приведение типов. Что-то типа такого (привожу упрощенный вариант):
template typename U> Arr & operator= (Arr & arr2) < for (int j = 0; j < len2; ++j) arr[j] = arr2[j]; return *this; >
Да и вообще в коде (1) мы уже не имеем возможности создавать как таковые динамические массивы, параметру шаблона нужно передавать константу. И функции, требующей на входе двумерный массив, не понятно нак передавать его, если он хранится в виде A, 10>, получается одномерный массив объектов (одномерных массивов целых чисел) — это не то что нам нужно.
Итак. Я хочу создать некий пользовательский тип(класс), который позволит работать вот так (примерно так):
< Arrayint>> a; //Здесь каким-то образом задаю обе размерности a[7][5] = 5; std::cout << a[7][5] << endl; Arrayint>> b; //Другого размера, нежели a b = a; //Копирует значения (те которые поместятся, т.к. размер может быть и меньше) b.reSize(50); //Перевыделяет память и копирует значения a.newSize(100); //Освобождает занятую память и выделяет новый блок под сто элементов Arrayint>> c(b); //Конструктор копирования, если у c и b разные мерности, //то хочется чтобы такой код был определён как ошибачный на стадии компиляции //И главная цель - вызов функции с прототипом похожим на вот такой func(int** a, int s1, int s2), //каким-нибудь простым способом, например таким: func(a.getPoint(), a.size(), a[0].size()); >
Спасибо большое всем кто прочитал и что-то придумал.
Ещё раз (кратко), я хочу:
Создать объект — многомерный массив. Он должен:
1. выделять память, освобождать память, не утруждая этим клиентский код;
2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух
звёздочек — любое количество звёздочек (равное мерности массива));
3. уметь менять свой размер по требованию, уже после создания (т.е. что-то типа reSize, newSize описанных
выше);
4. использовать конструкторы копирования, перегруженные операторы присваивания для массивов однинаковой
мерности и типа, но разных размерностей.
Помогите, поделитесь, пожалуйста, любыми мыслями (отсылать меня использовать готовые библиотеки не нужно, посылать совсем далеко то же), советами, как реализовать эти 4 пункта!
Искал, то что хочу не нашёл. В std есть valarry, но 2 пункт (а для него всё это и делалось) не удет с ними работать, да и 4 прийдётся переписать самому. Перечитал главу про шаблоны у Б. Страуструпа, прочитал про шаблоны у Р. Лафоре, листал А. Александреску (жёстко написано, не дорос я ещё до него).
Заранее огромное спасибо всем, кто хоть что-то напишет, прочитав моё сообщение!
(Я уже давно е. сь с этой идеей. (е. сь — еграюсь ))
Re: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Alexander G |
| Дата: | 07.09.08 09:16 |
| Оценка: |
Здравствуйте, Green Chest,
Смотрели boost::multi_array ?
GC>2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух
GC>звёздочек — любое количество звёздочек (равное мерности массива));
Возможно, этого там нет, т.к. внутри массив хранистя как одномерный. Остальное вроде есть.
Русский военный корабль идёт ко дну!
Re[2]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 07.09.08 09:33 |
| Оценка: |
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, Green Chest,
AG>Смотрели boost::multi_array ?
// Create a 3D array that is 3 x 4 x 2 typedef boost::multi_arraydouble, 3> array_type; typedef array_type::index index; array_type A(boost::extents[3][4][2]); // Обращение к элементам A[0][0][0] = 1;
Но самое лакомое — передавать массив в функции, ждущие указателя на указатель. Даже если для этого потребуется создать ещё один массив, временный, и скопировать в него всё.
Есть исходный код библиотек Boost, он свободно распространяется(это open-source проект?)?
Мне нужно доделать именно свою реализацию, понять как это работает.
Re[3]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Alexander G |
| Дата: | 07.09.08 09:59 |
| Оценка: |
Здравствуйте, Green Chest, Вы писали:
GC>Но самое лакомое — передавать массив в функции, ждущие указателя на указатель. Даже если для этого потребуется создать ещё один массив, временный, и скопировать в него всё.
Зачем копировать сами элементы ? Нужен просто массив [из массивов [из массивов . ]] указателей. Думаю, можно его реализовать как отдельный класс, не меняя multi_array.
Посмотрите, нет ли вообще готового в multi_array.
GC>Есть исходный код библиотек Boost, он свободно распространяется(это open-source проект?)?
Да.
здесь.
open-source проект, который можно использовать в коммерческих проектах, причём не обязательно упоминать его в бинарном дистрибутиве.
multi_array и всё на что она зависит вообще header-only.
Вообще, перед тем как изобретать велосипед, стоит поискать готовое. Особенно поискать в бусте. Например здесь
Автор: jazzer
Дата: 29.08.08
Автор: jazzer
Дата: 05.09.08
меня предотвратили от «самодеятельности».
Русский военный корабль идёт ко дну!
Re: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Clinch |
| Дата: | 07.09.08 10:53 |
| Оценка: |
Здравствуйте, Green Chest, Вы писали:
GC>Здесь, на rsdn много раз обсуждались многомерные массивы (представлять как одномерные и проч.), но я среди обсуждений не нашёл именно того, что мне нужно.
GC>Необходимо сделать объект — оболочку для массивов, для удобства работы с массивами. (Проблема стара как мир )
GC>Т.е. обычным на С++ выглядит следующее:
GC>
GC> < GC>//Размерность первая GC> const unsigned int s1 = 4; GC> //Размерность вторая GC> const unsigned int s2 = 8; GC> //Временный массив для передачи данных функции GC> int **arr = new int*[s1]; GC> for(unsigned int i=0; i arr[i] = new int[s2]; GC> //Заполняем массив GC> for(unsigned int i=0; i for(unsigned int j=0; j d[i][j] = ; GC> //Вызываем некий метод некого объекта(это всё не важно, главное что ему GC> //требуется указатель на указатель, являющийся массивом целых чисел) GC> //прототипа навроде такого: setAD2(int** a, unsgined int size1, unsigned int size2) GC> fv.setAD2(arr, s1, s2); GC> //Метод забрал часть данных из двухмерного массива в своё внутренее хранилище, GC> //о котором мы ничего не знаем и знать не хотим, массив нам больше не нужен GC> //Освобождаем память GC> for(unsigned int i=0; i delete[] arr[i]; GC> delete[] arr; GC>> GC>
GC>Утомляет всё это писать, хочется написать выделение и освобождение памяти раз и навсегда ( для всех массивов), чтобы можно было так:
GC>
GC> < GC>//Объявили массив и выделили память GC> Arrayint> a(10); GC> //Заполняем массив GC> for(unsigned int i=0; i d[i] = ; GC> //Вызвали функцию требующу указатель на инт, являющийся массивом и размер массива GC> funcAr(a.getPoint(), a.size()); GC> //Деструктор вызовется автоматически и GC> //беспокоится о не освобождении памяти не нужно GC>> GC>
GC>Это легко реализовать с помощью вот такого шаблона (привожу очень упрощенный вид):
GC>
GC>template typename type> class A GC> < GC>private: GC> type *arr; GC> public: GC> A() : arr(0) <>; GC> A(int x) new type[x];>; GC> type& opertor [] (int index) return arr[index];>; GC>>; GC>
GC>Однако в таком случае для n-мерного массива (в примере ниже n=2) потребуется опять таки выделять память для каждого измерения:
GC>
GC> < GC>Aint> > ob1(10); //Получается память будет выделена только под одно измерение, как выделить под другое? GC> a[3][8] = 5; //ошибка, обращаемся к памяти по "левому" адресу GC> //Возможно сделать некий метод класса А под названием getMem, выделяющий память и вызывать его так: GC> for(unsigned int i=0; i ob1[i].getMem(10); GC> a[3][8] = 5; GC> //всё отлично, память выделена GC> assert(a[3][8] == 5); GC>> GC>
GC>Решение рабочее, но не красивое — уж лучше вообще без объектов, просто int** и ему выделять память.
GC>Тогда пришла идея сделать шаблон с параметром, вот такой:
GC>
GC>template typename type, unsigned int size> class A GC> < GC>private: GC> type *arr; GC> public: GC> A() : new type[size];>; GC> type& opertor [] (int index) return arr[index];>; GC>>; GC>
GC>Тогда код (1)
GC>
GC> < GC>Aint, 10>, 10> ob1; GC> a[3][8] = 5; //всё отлично, память выделена GC>> GC>
GC>. работает. Но не более.
GC>Дальше начинаются извращения, например чтобы присваивать (кажется логичным массиву из 10 целочисленных элементов присвоить массив из 9 целочисленных элементов, просто скопировав 9 значений) надо делать приведение типов. Что-то типа такого (привожу упрощенный вариант):
GC>
GC>template typename U> Arr & operator= (Arr & arr2) GC> < GC>for (int j = 0; j < len2; ++j) GC>arr[j] = arr2[j]; GC> return *this; GC>> GC>
GC>Да и вообще в коде (1) мы уже не имеем возможности создавать как таковые динамические массивы, параметру шаблона нужно передавать константу. И функции, требующей на входе двумерный массив, не понятно нак передавать его, если он хранится в виде A, 10>, получается одномерный массив объектов (одномерных массивов целых чисел) — это не то что нам нужно.
GC>Итак. Я хочу создать некий пользовательский тип(класс), который позволит работать вот так (примерно так):
GC>
GC> < GC>Arrayint>> a; //Здесь каким-то образом задаю обе размерности GC> a[7][5] = 5; GC> std::cout Arrayint>> b; //Другого размера, нежели a GC> b = a; //Копирует значения (те которые поместятся, т.к. размер может быть и меньше) GC> b.reSize(50); //Перевыделяет память и копирует значения GC> a.newSize(100); //Освобождает занятую память и выделяет новый блок под сто элементов GC> Arrayint>> c(b); //Конструктор копирования, если у c и b разные мерности, GC> //то хочется чтобы такой код был определён как ошибачный на стадии компиляции GC> //И главная цель - вызов функции с прототипом похожим на вот такой func(int** a, int s1, int s2), GC> //каким-нибудь простым способом, например таким: GC> func(a.getPoint(), a.size(), a[0].size()); GC>> GC>
GC>Спасибо большое всем кто прочитал и что-то придумал.
GC>
GC>Ещё раз (кратко), я хочу:
GC>Создать объект — многомерный массив. Он должен:
GC>1. выделять память, освобождать память, не утруждая этим клиентский код;
GC>2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух
GC>звёздочек — любое количество звёздочек (равное мерности массива));
GC>3. уметь менять свой размер по требованию, уже после создания (т.е. что-то типа reSize, newSize описанных
GC>выше);
GC>4. использовать конструкторы копирования, перегруженные операторы присваивания для массивов однинаковой
GC>мерности и типа, но разных размерностей.
GC>
GC>
GC>Помогите, поделитесь, пожалуйста, любыми мыслями (отсылать меня использовать готовые библиотеки не нужно, посылать совсем далеко то же), советами, как реализовать эти 4 пункта!
GC>Искал, то что хочу не нашёл. В std есть valarry, но 2 пункт (а для него всё это и делалось) не удет с ними работать, да и 4 прийдётся переписать самому. Перечитал главу про шаблоны у Б. Страуструпа, прочитал про шаблоны у Р. Лафоре, листал А. Александреску (жёстко написано, не дорос я ещё до него).
GC>Заранее огромное спасибо всем, кто хоть что-то напишет, прочитав моё сообщение!
GC>(Я уже давно е. сь с этой идеей. (е. сь — еграюсь ))
Вот придумалось такое ( всякие проверки, методы и прочие ништяки не реализовыавл ).
Подойдёт — докрутишь сам ))
template < typename VAL_TYPE >class multiarray < public: multiarray ( int dimension,int elements ) :dim_(dimension) ,elem_(elements) ,arr ( 0 ) ,x(0) < totalSize_ = ( dim_ + 1 ) * ( sizeof ( VAL_TYPE ) * ( elem_ ) ); arr = new VAL_TYPE [ totalSize_ ]; >~multiarray() < delete[] arr; >multiarray& operator [] (int i) < ep = i; x += i * elem_; return *this; >operator VAL_TYPE& () < int p = x - ( elem_ - ep ); x = 0; return arr[p]; >multiarray& operator = ( VAL_TYPE val ) < int p = x - ( elem_ - ep ); x = 0; arr[p] = val; return *this; >multiarray& operator = ( multiarray& rhs ) < x = ep = 0; dim_ = rhs.dim_; elem_ = rhs.elem_; for ( int i = 0; i< totalSize_;i++ ) arr[i] = rhs.arr [ i ]; return *this; >private: int ep; int x; VAL_TYPE *arr; int dim_; int elem_; int totalSize_; >; #define VT std::string int _tmain(int argc, _TCHAR* argv[]) < multiarrayar(3,10); multiarray ar2(3,10); ar[10][4][1] = "First"; ar2 = ar; VT s = ar2[10][4][1]; printf("[ value = %s] ",s.c_str()); return 0; >
Re[2]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 07.09.08 11:28 |
| Оценка: |
Здравствуйте, Clinch, Вы писали:
C>#define VT std::string C>int _tmain(int argc, _TCHAR* argv[]) C> < C>multiarray ar(3,10); C> multiarray ar2(3,10); C> ar[10][4][1] = "First"; C> ar2 = ar; C> VT s = ar2[10][4][1]; C> printf("[ value = %s] C>",s.c_str()); C> return 0; C>> C>
Как передать этот объект функции требующей на вход двумерный(трёх, четырёх) массив?
Я понимаю как сфориморовать из линейного массива n-мерный. Хотя понимаю как из одномерного двумерный — создали массив указателей и в него записали указатели на части нашего большого одномерного.
Но если у нас в виде одномерного представлен трёхмерный и его нужно представить в «обычном» виде.
И как написать универсальный метод который будет возращать классический массив (т.е. указатели на указатели на указатели. ) мерности, равной мерности хранимого в этом объекте массива?
Нужен какой-то не стандартный подход.
Предлагаете забросить мою идею?
Re[4]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 07.09.08 11:32 |
| Оценка: |
Здравствуйте, Alexander G, Вы писали:
AG>здесь.
AG>open-source проект, который можно использовать в коммерческих проектах, причём не обязательно упоминать его в бинарном дистрибутиве.
AG>multi_array и всё на что она зависит вообще header-only.
AG>Вообще, перед тем как изобретать велосипед, стоит поискать готовое. Особенно поискать в бусте. Например здесь
Автор: jazzer
Дата: 29.08.08
Автор: jazzer
Дата: 05.09.08
меня предотвратили от «самодеятельности».
Ок, попробую пошариться в его исходниках и понять, что я могу уташить в свой велосипед.
Re[3]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Clinch | |
| Дата: | 07.09.08 12:11 | |
| Оценка: | 2 (1) | |
Здравствуйте, Green Chest, Вы писали:
GC>Здравствуйте, Clinch, Вы писали:
GC>
C>>#define VT std::string C>>int _tmain(int argc, _TCHAR* argv[]) C>>< C>> multiarray ar(3,10); C>> multiarray ar2(3,10); C>> ar[10][4][1] = "First"; C>> ar2 = ar; C>> VT s = ar2[10][4][1]; C>> printf("[ value = %s] C>>",s.c_str()); C>> return 0; C>>> C>> GC>
GC>Как передать этот объект функции требующей на вход двумерный(трёх, четырёх) массив?
Хм, я либо не понял в чем тут подвох, но почему бы не так
// Добавлено в класс определение typedef typename VAL_TYPE value_type; typedef multiarray StringArray; void someFunction( StringArray &ar ) < StringArray::value_type s = ar[2][2]; // value_type - добавлено в классе ( typedef typename VAL_TYPE value_type ) fprintf(stdout,"At 2,2 = %s",s.c_str()); > . StringArray sa(4,4); sa[2][2] = "Hello"; someFunction ( sa ); .
GC>Я понимаю как сфориморовать из линейного массива n-мерный. Хотя понимаю как из одномерного двумерный — создали массив указателей и в него записали указатели на части нашего большого одномерного.
GC>Но если у нас в виде одномерного представлен трёхмерный и его нужно представить в «обычном» виде.
ЭЭ. ну так в классе у нас и есть одномерный массив, и его можно трансформировать в любой другой, изменяя поле multiarray::elem_ + ещё реинициализация
добавить метод, что-то вроде multiarray::transformTo(int rowa,int cols), нет ?!
Или мы о разных вещах ? ))
GC>И как написать универсальный метод который будет возращать классический массив (т.е. указатели на указатели на указатели. ) мерности, равной мерности хранимого в этом объекте массива?
Ого, вот так хочется ?
StringArray sa(4,4); std::string ***pStr = sa; // !?
GC>
GC>Нужен какой-то не стандартный подход.
GC>Предлагаете забросить мою идею?
Не, бросать не надо. мне тоже делать нечего ! ))
Re[4]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 07.09.08 12:56 |
| Оценка: |
Здравствуйте, Clinch, Вы писали:
GC>>Как передать этот объект функции требующей на вход двумерный(трёх, четырёх) массив?
C>Хм, я либо не понял в чем тут подвох, но почему бы не так
C>C> // Добавлено в класс определение
C> typedef typename VAL_TYPE value_type;
C> typedef multiarray StringArray; C> void someFunction( StringArray &ar ) C> < C>StringArray::value_type s = ar[2][2]; // value_type — добавлено в классе ( typedef typename VAL_TYPE value_type ) C> fprintf(stdout,"At 2,2 = %s",s.c_str()); C> > C> . C> StringArray sa(4,4); C> sa[2][2] = "Hello"; C> someFunction ( sa );
Функция, которая просит на вход (type** a) описана в недрах закрытой библиотеки. И просить (StringArray &ar) она уже не может. Мы должны принять её такой, какая она есть.
C>Ого, вот так хочется ?
C>C> StringArray sa(4,4); C> std::string ***pStr = sa; // !?
Да. Именно так и хочется, конкретнее:
< int* ar1; Arrayint> tmp_ar1(10); ar1 = tmp_ar1.getPoint(); int** ar2; Array>> tmp_ar2(10,20); ar2 = tmp_ar2.getPoint(); int*** ar3; Array>> tmp_ar3(10,20,5); ar3 = tmp_ar3.getPoint(); . int***. ** arN; //Здесь указатель на указатели на указатель. в кол-ве N штук Array>*****>>> tmp_arN(10,20,5, . 50,10); //Здесь N параметров — размер для каждой мерности arN = tmp_arN.getPoint(); >
C>Не, бросать не надо. мне тоже делать нечего ! ))
Если это получится, то это будет офигенно удобный динамический массив. Удобней, чем массивы в OP (Delphi).
Re: Преобразование T* в T*** при известной размерности
| От: | Alexander G | |
| Дата: | 07.09.08 13:10 | |
| Оценка: | 1 (1) | |
Используется Boost.MultiArray, но фактически класс не привязан к boost::multi_array.
Более удобный интерфейс можно получить, если привязать к boost::multi_array, чтобы он сам брал экстенты из него. Или можно к своему велосипеду прикрутить.
Не тестировал особо, просто набросок
#include #include templatetypename element, size_t NumDims> class multi_array_multi_pointer < template struct dim_impl; template<> struct dim_impl < typedef typename element * pointer_type; pointer_type ptr; void init(element ** pointer, size_t const* dim) < ptr = *pointer; (*pointer) += *dim; >pointer_type get() const < return ptr; > >; template struct dim_impl < typedef dim_impl Inner; typedef typename Inner::pointer_type inner_pointer, * pointer_type; boost::scoped_array data; boost::scoped_array pointers; void init(element ** pointer, size_t const* dim) < data.reset(new Inner[*dim]); pointers.reset(new inner_pointer[*dim]); ptr = pointers.get(); for (size_t i = 0; i != *dim; ++i) < data[i].init(pointer, dim + 1); pointers[i] = data[i].ptr; >> pointer_type get() const < return pointers.get(); > >; typedef dim_impl dims_t; dims_t dims; public: typedef typename dims_t::pointer_type pointer_type; multi_array_multi_pointer(element * data, size_t const (&extents)[NumDims]) < dims.init(&data, extents); >pointer_type get() < return dims.get(); > >; int main() < // Create a 3D array that is 3 x 4 x 2 typedef boost::multi_arraydouble, 3> array_type; typedef array_type::index index; array_type a(boost::extents[3][4][2]); // Обращение к элементам a[0][0][0] = 1; a[2][0][1] = 2; a[0][3][0] = 3; a[2][3][1] = 4; double * i = a.origin(); size_t ss[] = ; multi_array_multi_pointerdouble, 3> mp(i, ss); double *** mp_raw = mp.get(); printf("%f %f %f %f", mp_raw[0][0][0], mp_raw[2][0][1], mp_raw[0][3][0], mp_raw[2][3][1]); return 0; >
Каким я вижу интерфейс в случае boost::multi_array:
templateclass MultiArray> class multi_array_raw_pointer < public: explicit multi_array_raw_pointer(MultiArray const& array); // принимает класс, реализующий boost::multi_array. // плюс неявное копирование и присваивание. pointer_type get(); // возвращает T*** /* operator pointer_type() - этого не надо */ > templateclass MultiArray> multi_array_raw_pointer make_raw_pointer(MultiArray const& array) < return multi_array_raw_pointer(array); >
void legacy_api(double***); typedef boost::multi_arraydouble, 4> A; A a; legacy_api(make_raw_pointer(a).get()); или multi_array_raw_pointer rp(a); legacy_api(rp.get());
Русский военный корабль идёт ко дну!
Re[2]: Преобразование T* в T*** при известной размерности
| От: | Green Chest |
| Дата: | 07.09.08 17:19 |
| Оценка: |
Здравствуйте, Alexander G, Вы писали:
AG>использование:
AG>
AG>void legacy_api(double***); AG>
Меня это натолкнуло на мысль и я написал для проверки следующее:
class test < private: static unsigned int val; public: int x; test() ; >; unsigned int test::val = 0; //Обратите внимание на то что для каждой размерности //память выделяется совершенно одинаково, //не зависимо от типа элементов массива //и от итоговой общей размерности массива //Это я и положу в основу многомерного массива. int main() < const unsigned int S = 3; int *b = new int[S]; test ****a = reinterpret_cast(b); int *b_psev; int *c; for(unsigned int i=0; inew int[S]; b_psev = reinterpret_castint*>(b); b_psev[i] = reinterpret_castint>(c); for(unsigned int j=0; jnew int[S]; b_psev = reinterpret_castint*>(b[i]); b_psev[j] = reinterpret_castint>(c); for(unsigned int k=0; knew test[S]; > > for(unsigned int i=0; ifor(unsigned int j=0; jfor(unsigned int k=0; kfor(unsigned int l=0; l" "; cout " | " cout " ||| " cout >
Сейчас я это всё ещё доосмысливаю, приведу к нужному виду и наверное будет у меня шаблон многомерного массива
Re: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Кодт | |
| Дата: | 08.09.08 06:54 | |
| Оценка: | 2 (1) | |
Здравствуйте, Green Chest, Вы писали:
GC>Ещё раз (кратко), я хочу:
GC>Создать объект — многомерный массив. Он должен:
GC>1. выделять память, освобождать память, не утруждая этим клиентский код;
Ну это дело нехитрое. std::vector умеет всё, тут даже велосипедировать не нужно.
GC>2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух звёздочек — любое количество звёздочек (равное мерности массива));
А вот здесь бы я попробовал рефакторить клиентский код.
Дело в том, что правильный тип гиперкуба — это int *const *const . *const. То есть, мы вправе менять элементы, но не вправе менять структуру.
К тому же, int*** — это не гиперкуб, а в общем случае jagged array. Каждый подмассив может иметь произвольный размер.
Вопрос в цене этой операции.
Когда-то на RSDN была статья о том, как создать матрицу с очень быстрой вставкой-удалением и строк, и столбцов. Но естественно, что внутреннее представление там было весьма затейливое.
Думаю, что здесь тебе важно осмыслить: что происходит с данными, когда ты меняешь размеры. Не «как это реализовать» — это второй вопрос. А
— что остаётся на месте, что двигается;
— какие асимптотики;
Например, однократное изменение размера вектора — линейно, так как требует копирования всех данных в новый блок; серия изменений — благодаря резервированию — получается дешевле; а у Б-дерева из-за блочной структуры — и однократное изменение логарифмично.
Ну и, чтоб два раза не вставать:
— нужно ли получать срезы по произвольным размерностям; нужно ли получать подмассивы; какие асимптотики у их порождения;
— какие асимптотики у доступа к отдельным элементам; как эффективно использовать кэш;
Здесь дело в том, что если матрица большого размера развёрнута по строкам, а ты бегаешь по столбцам — они будут вытеснять друг друга. То есть — это вопрос типичного применения. Где-то удобнее по строкам, где-то по столбцам, а где-то по клеточкам M*M.
Все эти вопросы нужно включить самому себе в ТЗ.
GC>4. использовать конструкторы копирования, перегруженные операторы присваивания для массивов однинаковой мерности и типа, но разных размерностей.
А вот это как раз очень просто.
Способ номер 1. Равняйсь-смирно.
Сделал ресайз (привёл приёмник к размеру источника) да и выполнил присваивание.
Но тут опять удобно абстрагироваться от типа источника. Всё, что от него требуется — это иметь функцию, возвращающую размеры, и функцию доступа к элементу.
Тогда ты получишь код, одинаково приспособленный и к голым int***, и к vector>>, и к твоим контейнерам, и к чему угодно.
Способ номер 2. Выкрасил и выбросил.
Пусть контейнер умеет клонировать свои данные.
Тогда конструктор копирования — это присвоение полям свежесозданного объекта этих клонированных данных.
А оператор присваивания — это создание временного объекта-копии источника, обмен полей с объектом-приёмником и убийство объекта-копии (вместе со старыми данными приёмника).
YourContainer::operator=(YourContainer const& src) < if(this == &src) return; YourContainer(src).swap(*this); >
Перекуём баги на фичи!
Re[2]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 08.09.08 08:22 |
| Оценка: |
Здравствуйте, Кодт, Вы писали:
GC>>1. выделять память, освобождать память, не утруждая этим клиентский код;
К>Ну это дело нехитрое. std::vector умеет всё, тут даже велосипедировать не нужно.
Разумеется, с этим проблем нет никаких.
GC>>2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух звёздочек — любое количество звёздочек (равное мерности массива));
К>А вот здесь бы я попробовал рефакторить клиентский код.
К>Дело в том, что правильный тип гиперкуба — это int *const *const . *const. То есть, мы вправе менять элементы, но не вправе менять структуру.
К>К тому же, int*** — это не гиперкуб, а в общем случае jagged array. Каждый подмассив может иметь произвольный размер.
Да, какждый подмассив может иметь произвольный размер, это легко реализовать — конструктор с переменным числом параметров. С помощью рекурсии и reinterpret_cast можно однотипно выделять память для каждой мерности (в другой веточке моей темки — в ответе на пост Alexander G я написал код, который это делает, он пока оторван от объекта (сейчас занимаюсь созданием полноценного класса), но делает он именно то что я хотел).
Мне не нужно куб. Достаточно массив, элементами которого являются массивы, элементами которых, являются массивы, элементами которых являются какие-либо объекты. С помощью рекурсивного однотипного выделения памяти каждой мерности, элементы самого верхнего массива (первой мерности) будут далеко друг от друга, но вообще эта реализация не критична к быстродействию. Она должна работать приемлимо в небольших прикладных программах (например, хранить таблицу double-значений размером так 100х1000 и давать не накладный доступ к её элементам). И она делает даже больше, скорость работы мне вполне нравится (под пятимерный массив 10х10х10х10х10 на моей машинке (простенький компутер) выделяет память (вызывает для каждого создаваемого объекта конструктор, который при проводимых мною замерах содержал одно присваивание int’а int’у) менее чем за 30 мс. Трёхмерный 20х20х20 — менее 1 мс). Она универсальна.
GC>>3. уметь менять свой размер по требованию, уже после создания (т.е. что-то типа reSize, newSize описанных выше);
К>Вопрос в цене этой операции.
К>Все эти вопросы нужно включить самому себе в ТЗ.
Понимаю. Но третий (и четвёртый) пункт описывает не типичные действия для создаваемого мною объекта, а следовательно под них не стоит его «затачивать». Произвести замеры скорости работы, когда доделаю, интересны циферки-числа?
GC>>4. использовать конструкторы копирования, перегруженные операторы присваивания для массивов однинаковой мерности и типа, но разных размерностей.
К>А вот это как раз очень просто.
Да, как и с пунктом 1 проблем нет, просто в первом моём сообщении в этой теме был вариант с шаблоном, который используется так Array,5> — требовались дополнительные «телодвижения» для реализации присваивания. В объекте, который я сейчас делаю проблем с этим нет, т.к. он описывается так: Array
Спасибо большое за ответ.
Re[3]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Кодт | |
| Дата: | 08.09.08 10:10 | |
| Оценка: | +1 | |
Здравствуйте, Green Chest, Вы писали:
К>>К тому же, int*** — это не гиперкуб, а в общем случае jagged array. Каждый подмассив может иметь произвольный размер.
GC>Да, какждый подмассив может иметь произвольный размер, это легко реализовать — конструктор с переменным числом параметров. С помощью рекурсии и reinterpret_cast можно однотипно выделять память для каждой мерности (в другой веточке моей темки — в ответе на пост Alexander G я написал код, который это делает, он пока оторван от объекта (сейчас занимаюсь созданием полноценного класса), но делает он именно то что я хотел).
GC>Мне не нужно куб. Достаточно массив, элементами которого являются массивы, элементами которых, являются массивы, элементами которых являются какие-либо объекты. С помощью рекурсивного однотипного выделения памяти каждой мерности, элементы самого верхнего массива (первой мерности) будут далеко друг от друга, но вообще эта реализация не критична к быстродействию. Она должна работать приемлимо в небольших прикладных программах (например, хранить таблицу double-значений размером так 100х1000 и давать не накладный доступ к её элементам). И она делает даже больше, скорость работы мне вполне нравится (под пятимерный массив 10х10х10х10х10 на моей машинке (простенький компутер) выделяет память (вызывает для каждого создаваемого объекта конструктор, который при проводимых мною замерах содержал одно присваивание int’а int’у) менее чем за 30 мс. Трёхмерный 20х20х20 — менее 1 мс). Она универсальна.
Под словом «гиперкуб» я имел в виду прямоугольный гипер-параллелепипед. То есть, у каждой координаты свой диапазон.
И противопоставил этому jagged array — массив независимых друг от друга массивов.
Самая простая реализация JA — это vector> — каждый элемент ресайзишь как хочешь.
Всё-таки тебе нужно не мыслить в терминах С++ (где там шаблон, где там массив), а в терминах технического задания.
Буквально, сесть и написать:
«Я хочу контейнер, который»
— хранит многомерный массив
— размерность пространства есть свойство типа этого контейнера
— диапазоны, напротив, есть свойство каждого объекта этого типа
— имеет фасад в виде n-кратного применения оператора []
— имеет фасад в виде приведения к голому T *const *const . *const и, на кой-то чёрт, то же самое без константности (сам себе злобный буратино)
— допускает неторопливый ресайз, поскольку операции ресайза будут редки
И более того, «я хочу контейнер, который будет использоваться для»
— представления тензоров
— представления многомерных картинок
— представления таблиц (i1,i2. in)->T
и так далее — здесь ты должен определиться.
Иначе твой труд — с разбега в никуда.
Если думать о T*** как о фасаде, а не как о внутреннем устройстве самого контейнера, то несложно родить адаптер — объект, хранящий T*** плюс всё необходимое.
И порождать его из вектора векторов векторов.
Перекуём баги на фичи!
Re[4]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Green Chest |
| Дата: | 08.09.08 15:42 |
| Оценка: |
Здравствуйте, Кодт, Вы писали:
К>Всё-таки тебе нужно не мыслить в терминах С++ (где там шаблон, где там массив), а в терминах технического задания.
К>Буквально, сесть и написать:
К>»Я хочу контейнер, который»
К>- хранит многомерный массив
К>- размерность пространства есть свойство типа этого контейнера
К>- диапазоны, напротив, есть свойство каждого объекта этого типа
К>- имеет фасад в виде n-кратного применения оператора []
К>- имеет фасад в виде приведения к голому T *const *const . *const и, на кой-то чёрт, то же самое без константности (сам себе злобный буратино)
К>- допускает неторопливый ресайз, поскольку операции ресайза будут редки
Вообще, то что вы написали — мне очень понравилось.
Особенно вот это:
К>- размерность пространства есть свойство типа этого контейнера
К>- диапазоны, напротив, есть свойство каждого объекта этого типа
К>- имеет фасад в виде n-кратного применения оператора []
К>- имеет фасад в виде приведения к голому T *const *const . *const и, на кой-то чёрт, то же самое без константности (сам себе злобный буратино)
Эти четыре пункта — всё что мне вообще нужно, остальное всё — это уже, так скажем, дополнительные возможности.
Под тензором вы просто понимал матрицу или нечто иное?
К>
К>Если думать о T*** как о фасаде, а не как о внутреннем устройстве самого контейнера, то несложно родить адаптер — объект, хранящий T*** плюс всё необходимое.
Это и без векторов хорошо «рожается».
Re[5]: Универсальный шаблон массива (n-мерного, n >= 1)
| От: | Кодт |
| Дата: | 09.09.08 09:28 |
| Оценка: |
Здравствуйте, Green Chest, Вы писали:
GC>Вообще, то что вы написали — мне очень понравилось.
Пррроклятье! Я сделал за тебя твою работу!
GC>Под тензором вы просто понимал матрицу или нечто иное?
Под тензором я понимаю многомерный массив с тучей индексов, с характерными операциями над ним.
Аффинор — это очень частный случай тензора, наиболее применимый в жизни.
Для тензоров (да и для матриц) существенно итерирование по каждой координате.
Для картинок — быстрый доступ к окресностям точки.
Поэтому там получаются разные стратегии влезания в кэш.
Класс Matrix: реализовать шаблонный класс для двумерных массивов
Доброго времени суток. У меня вопрос: я создал класс Array со внутренним динамическим массивом и объекты этого типа смог создать и я ими пользуюсь как обычными массивами. Подобный класс хочу создать для двумерного массива с именем Matrix. Как создать этот класс, помогите пож-та. Заранее спасибо.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
#include #include #include using namespace std; template typename T> class Array { T* mass; int len; public: Array() { this->len = 0; this->mass = NULL; } Array(int _len) { this->len = _len; this->mass = new T [this->len]; } ~Array() { delete [] this->mass; } T& operator [] (int index) { return this->mass[index]; } void Free() { delete [] this->mass; this->mass = NULL; this->len = 0; } }; /* template class Matrix Array < Array>* mass; int rows; int cols; public: Matrix() this->rows = this->cols = 0; this->mass = NULL; > Matrix(int _rows, int _cols) : rows(_rows), cols(_cols) this->mass = new Array < Array> (this->rows); for (int i = 0; i < this->rows; i++) this->mass[i] = new Array(this->cols); > Array& operator [] (int index) return this->mass[index]; > void Free() for (int i = 0; i < this->rows; i++) mass[i].Free(); this->rows = this->cols = 0; this->mass = NULL; > >; */ int main() { srand(time(0)); Arrayint> mass(15); for (int i = 0; i 15; i++) mass[i] = rand() % (99 - 10 + 1) + 10; for (int i = 0; i 15; i++) cout [ i] <"\t"; mass.Free(); /* int M, N; cout > M; cout > N; Matrix matr(M, N); for (int i = 0; i < M; i++) for (int j = 0; j < N; j++) matr[i][j] = rand() % (99 - 10 + 1) + 10; cout > cout > matr.Free(); */ return 0; }
Реализация шаблона класса Массив (двумерный)
Нужен шаблон класс Array, являющийся аналогом двумерных массивов. Делать решил на основе одномерных. Убил полдня, но так и не смог. Основная проблема с перегрузкой оператора индексирования. Пробовал с помощью одномерных Array
template < class T >class Array < public: //конструкторы Array(int sizeL,int sizeW); Array(const Array& rhs); ~Array() //операторы Array& operator = (const Array&); T& operator [] (int offsetL,int offsetW) < if (offsetL>=0&&offsetL=0&&offsetW const T& operator [] (int offsetL,int offsetW) const < if (offsetL>=0&&offsetL=0&&offsetW //дружественная функция для переопределения оператора вывода template < class X >friend ostream& operator&); //методы доступа int GetSizeL() const int GetSizeW() const //определение класса исключений с множественным наследованием class xBoundary <>; //обращение к элементу вне массива class xSize //ошибки связанные с заданием размера < public: virtual void PrintError() >; class xBig :public xSize < public: virtual void PrintError() >; class xSmall :public xSize < public: virtual void PrintError() >; class xZero :public xSmall < public: virtual void PrintError() >; class xNegative :public xSize < public: virtual void PrintError() >; private: T *pType; int itsSizeW; int itsSizeL; >; //определение конструкторов иметодов шаблона-класса Массив template < class T >ostream& operator & theArray) < for (int i=0;ireturn output; > template < class T >Array::Array(int sizeL,int sizeW): itsSizeL(sizeL),itsSizeW(sizeW) < //проверка на ошибки размера массива if (sizeL==0||sizeW==0) throw xZero(); if (sizeL>100||sizeW>100) throw xBig(); if (sizeL <1||sizeW<1) throw xNegative(); if (sizeL<2||sizeW<2) throw xSmall(); pType=new T[sizeL][sizeW]; for (int i=0;itemplate < class T >Array::Array(const Array& rhs) < itsSizeL=rhs.GetSizeL(); itsSizeW=rhs.GetSizeW(); pType=new T[itsSizeL,itsSizeW]; for (int i=0;itemplate < class T >Array& Array::operator = (const Array& rhs) < if (this==&rhs) return *this; delete [] pType; itsSizeL=rhs.GetSizeL(); itsSizeW=rhs.GetSizeW(); pType=new T[itsSizeL,itsSizeW]; for (int i=0;i//********************Главная функция*********************************** int main() < try //обработчик ошибок < ArrayworkArray(8,2); for (int i=0;i>workArray[i]; cout catch (Array::xBoundary) catch (Array::xSize& theException) return 0; >
Ошибки при компиляции:
Отслеживать
218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков