템플릿으로 구조를 마음대로 변형할 수 있는 다차원 배열을 만들고 싶습니다.

jinserk의 이미지

제목과 같이, 템플릿으로 구조를 마음대로 변형할 수 있는 배열을 만들고 싶습니다.

1. n차원 배열로 사용 가능해야 합니다.

2. 배열 내 데이터를 옮기지 않고, 차원을 바꿀 수 있어야 합니다. 예를 들어서
1x10 -> 2x5 -> 5x2 등으로 변경할 수 있어야 합니다.

3. 배열 끝이나 중간에 데이터를 임의로 삽입하거나 삭제할 수 있어야 합니다.

4. 배열의 일부분을 뜯어낼 수 있어야 합니다. 이때 데이터를 복사해서 새로운 메모리를 만들지 않고
단순히 일부분을 참조만 하고 싶습니다. 예를 들어서
100x100 의 배열에서 (3:4)x(7:8) (m:n 은 m 부터 n 까지의 인덱스) 을 참조할때 이것이
2x2 배열처럼 외부에서 보이도록 하고 싶습니다. (즉 인덱스가 (0:1)x(0:1) 로 보일 수 있게)

이런 배열을 만들려면 어떤식으로 클래스를 만들어야 할까요?
지금 딱히 떠오르는 방법은 stl 의 map 을 사용하는 방법 뿐인데.. 4번이 만만치가 않네요.

----------------------------------------

예전에 문의드린 질문인데, 다시금 끌어올려봅니다.
아래와 같은 코드를 작성했습니다.

    template <typename T, int DIM> class array
    {
        private:
            array<T, DIM-1>*   con_;  <---------------- error
            T*      mem_;
            int     pos_;   // current position
            int     sz_;
 
        public:
            array() {
                mem_ = NULL;
                pos_ = 0;
            }
 
            array(int s1) {
                mem_ = new T[s1];
                sz_ = s1;
                pos_ = 0;
            }
 
            array(int s1, int s2) {
                sz_ = s1;
                con_ = new array<T,1> [s1];
                pos_ = 0;
            }
 
            ~array() {
                if (DIM > 1)
                    for (int i = 0; i < sz_; i++)
                        con_[i].~array();
                if (!mem_)
                    delete [] mem_;
            }
 
            inline T& operator() (int i1) {
                return mem_[i1];
            }
 
            inline T& operator() (int i1, int i2) {
                return mem_[i1](i2);
            }
 
            inline void reset_pos(void) {
                pos_ = 0;
            }
 
            inline int push(T& e) {
                int over = 0;
 
                if (DIM > 1) {
                    over = con_[pos_].push(e);
                    if (over) {
                        pos_++;
                    }
                    return 0;
                }
 
                mem_[pos_++] = e;
                if (pos_ == sz_) {
                    pos_ = 0;
                    return 1;
                }
                return 0;
            }
 
            inline int size(void) {
                return sz_;
            }
    };

좀 복잡한데, 어쨌든 재귀적으로 배열을 쌓아서 다차원 배열을 만들려는 어줍잖은 시도입니다.
아래 리플 달아주신 내용을 이제야 조금 이해해서, 그렇게 구현하려고 노력중인데요.

템플릿의 <> 내에 dimension 을 적으려고 하니, 내부의 하위 클래스 포인터 선언에서
DIM-1 이 무한 호출되면서 컴파일러가 배를 쨉니다.

어떤식으로 접근해야 할지 감이 안잡히는군요. <> 내에 dimension 을 적는것이
적절치 않은 것인지..

도움 부탁드립니다. 감사합니다.

jinserk의 이미지

쉽게 말해서, MATLAB 의 matrix 와 같은 배열을 만들고 싶은겁니다.
다만, 메모리 복사가 빈번히 일어나지 않으면서 각 원소에 고속 접근이 가능하고 배열 구조나 크기를 가변할 수 있는..
넘 많은걸 바라는걸까요? -_-

Leo.

klara의 이미지

저도 방금 소개 받아서 퍼포먼스는 어떨지 모르겠지만, boost::multi_array 가 있습니다.

jinserk의 이미지

boost 의 multi_array 를 보긴 했는데

2, 3 번이 해결이 안됩니다. :(

2 번은 되는 것 같기도 하긴 한데 제가 필요한 것에 살짝 미달하네요.
단순히 dimension 만 바꾸는 것 뿐만이 아니라 matrix transpose 가 가능해야 합니다.
예를 들어서 A[3][4] 가 있을 때 B = A.transpose() 이면 A[1][2] = B[2][1] 이 되도록 해야 하는데
boost 의 multi_array 는 A[1][2] = B[1][2] 인 듯 합니다.

Leo.

winner의 이미지

서로 상반되는 요구사항을 원하시는 느낌이네요.

jinserk의 이미지

어떤 부분이 상반되는지 알려주실 수 있나요?
정말로 궁금해서 여쭤보는 겁니다. 아예 구현이 불가능한 조건인건지 알고 싶어서요.

Leo.

pensaku의 이미지

1. 그냥 vector를 사용하면 되겠네요..

class MyArray {
private:
	bool mIsContainer;
	std::vector&lt;MyArray> *mContainer; // 둘 중 하나 골라서 필요에 따라 할당
	std::vector&lt;double> *mNumbers;
};

이런 클래스를 쓰세요... 자세한 사항은 생략할게요.

2. 이것 역시 vector...

3. 이것 역시 vector로 가능하죠...

4. 메모리를 새로 할당하기 싫다면 이터레이터의 vector를(이터레이터들이 담긴 새로운 vector) 만들어서 접근하게 하면 되겠죠. 굳이 그렇게 안해도 코드에서 직접 실시간으로 접근만 그렇게 되도록 하거나요.. 물론 새로 만든 행렬에 뭔가 추가하려면 새로 복사해야겠죠.

transpose는 그냥 메모리 접근 방식을 달리 하면 되는 걸테고요.

실제로 구현하자면 굉장히 복잡하게 되겠군요. 이런 수학 라이브러리가 분명 있을테니 검색 ㄱㄱ

jinserk의 이미지

1번부터 막히네요.
class 정의할 때 내부에 자신의 클래스를 사용할 수가 있나요?
재귀적 정의(?)가 될 듯 한데..

Leo.

pensaku의 이미지

됩니다. 초보시면 이거 구현하시는데에 조금은 무리가 있으실 듯... 걍 검색해서 찾으세영

jick의 이미지

뭐랄까, "가볍고 화면이 넓으면서 튼튼하고 성능좋고 배터리 오래가는데 값이 싼 노트북"을 원하시는 느낌인데요...

원하시는 모든 operation을 O(1) time에 처리하는 방법은 없을 것 같습니다. 어떤 목적으로 쓰려는지 목적을 잘 생각하시고, 각각의 operation을 대략 몇 번 정도 수행할 것이며 다루려고 하는 데이터의 크기는 얼마인지 생각한 다음 "이 요구사항 중 이것만은 절대 양보할 수 없다 (나머지는 좀 느려도 된다)"라는 것을 두 가지 정도 골라보심이 어떨까 싶습니다.

그리고 data copy를 안하는 게 능사가 아닙니다. 데이터를 임의로 재구성하고 잘라내서 일부를 가리키면서도 copy를 안하려면 "데이터의 어느 부분을 누가 가리키고 있음"을 기억하는 것 자체가 엄청난 자료구조가 되는데 코드의 복잡함도 문제려니와 이를 관리하는 게 overhead가 되어서 그만큼 속도가 떨어집니다.

예를 들자면, 1000*1000짜리 행렬 A를 만들고 그 중의 2*2를 떼어서 B가 가리키게 한 다음 A를 delete했습니다. A가 사용하던 메모리는 어떻게 될까요?

1. B가 없어질 때까지 기다리다 반납 ===> 메모리 사용량이 엄청나게 뻥튀기될 수 있음

2. 바로 반납하고 B의 자료는 다른 곳에 복사 ===> 그러면 A가 "A에서 떼어낸 자료구조"를 모두 가리키고 있어야 합니다. (게다가 얘들은 자기들끼리 서로 다시 떼어내고, 구조를 바꾸고, 중간에 행을 추가할 수 있죠. 이걸 다 관리해야 합니다.) 게다가, B의 내부구조를 바꾸는 동안 다른 thread가 B를 사용하려고 하면? Mutex를 걸면 deadlock 문제는?

3. A의 자료중 2*2 영역만 빼고 나머지를 반납 ===> custom memory handler가 필요합니다. (자세한 설명은 생략... 쿨럭...)

jinserk의 이미지

위 pensaku 님이 제시하신 방법대로 가보고 있는데 어렵네요.
질문 수정내용을 보시고 도움 부탁드립니다.

Leo.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.