은근히 자주 쓰이는 Alter 명령어를 정리함.

아래 없는 내용은 계속 추가할 예정임.

 

앞에 my, old, new 가 붙은 건 사용자가 정의한 값이다.

 

♣ Primary Key 설정

Alter Table my_table Add constraint primary key (my_field) ;

 

♣ 열 삭제

Alter Table my_table Drop my_column ;

 

♣ 열 추가

(뒤에 열 type 은 맞게 수정해 준다)

Alter Table my_table Add new_column VARCHAR(32) ;

 (my_column 뒤에 new_column 을 추가함)

Alter Table my_table Add new_column VARCHAR(32) After my_column ;

 (맨 앞에 new_column 을 추가함)

Alter Table my_table Add new_column VARCHAR(32) First ;

 

 

♣ 열 이름 변경

(새 열 뒤에 type 이 추가돼야 함)

Alter Table my_table Change old_column new_column VARCHAR(32) ;

 

♣ 열 속성 변경

Alter Table my_table Modify my_column VARCHAR(32) ;

 

♣ AUTO_INCREMENT 열 재정렬

아래와 같이 하면 10번부터 입력이 되게 된다.

Alter Table my_table AUTO_INCREMENT=10 ;

 

♣ 인덱스에 새 항목 추가

Alter Table my_table ADD INDEX(my_column) ;

 

 

 

 

 

 

본 글은 새로 쓴 글로 통합합니다.

아래는 링크 클릭하시면 새로운 글로 이동합니다.

 

Zebra ZPL 의 GFA 명령어 및 Bitmap 데이터 압축하기

Link : https://hahaite.tistory.com/326

 

 

♣ 도움받은 사이트

 

♣ Open SSH Server 설치

2017년 후반 쯤에 Windows 10 에서 Open SSH Server Beta 버전을 지원하기 시작한 것 같다.

지금(18년 7월) 은 Beta 버전이 아닌 정식 버전으로 지원하고 있다.

베타버전과 정식 버전은 설정상 약간의 차이가 있으며, 현재 구글링해서 나오는 부분은 대부분 Beta 버전을 기준으로 설명하고 있다.

본 문서는 정식버전을 기준으로 설명한다. 

 

1. Windows 10 이 아니면 Windows 10 으로 업그레이드 한다.
   현재 (2018년 7월) Windows 10 에서 OpenSSH 설치를 제공하고 있다.
   이것저것 조사하고 설치해 본 후 내린 결론은, Windows 10 에서 제공하는 Open SSH Server를 서버를 설치하는게 정신건강에 이롭다.

 

2. 설정 -> 앱 -> 선택적 기능관리 -> 기능추가 -> OpenSSH 서버 선택하여 설치한다.

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

 

 

 

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

 

 

 

♣ OpenSSH Server 경로

C:\Windows\System32\OpenSSH 에 설치된다.

 

Beta 버전인 경우, SSH Key 를 직접 생성해야 했는데

현 버전은 OpenSSH 를 구동시키니 자동으로 생성되었다. 아래 경로에 키가 없으면 생성하는 듯 하다.

아래 경로는 시스템 경로이므로 탐색기에서 보기 -> 숨김항목을 체크해야 탐색기에 나타난다.

 

c:\ProgramData\ssh

 

authorized_keys 에는 인증받은 public key 가 저장되며 각 윈도우 계정 디렉토리의 .ssh 에 저장된다.

만약 윈도우 계정이 hahaite 라면,

 

C:\Users\hahaite\.ssh\authorized_keys

 

에 위치한다.

 

참고로,

.ssh 디렉토리는 앞에 점(dot) 이 있어 탐색기 -> 새폴더로 생성이 안된다.

이에 Dos 나 PowerShell 에서 "mkdir .ssh" 라고 명령어로 디렉토리를 생성하였다.

 

♣ OpenSSH Server 실행

PowerShell 을 관리자 모드로 실행한다.

 

 

 

PowerShell 에서,

Get-Service sshd 로 현재 OpenSSH 의 실행 여부를 확인할 수 있다.

 

아래 명령어로 실행, 중지, 재실행할 수 있다.

 

Start-Service sshd

Stop-Service sshd

Restart-Service sshd

 

 

♣ OpenSSH Server 접속

Linux 에선 아래와 같이 접속하여 OpenSSH 접속을 확인한다.

$ ssh hahaite@172.16.253.10

 

Windows 에선 Putty 를 사용하여 접속됨을 테스트하였다.

만약 putty 접속 때 아래와 같은 메시지가 나타나면,

(Disconnected: Server protocol violation: unexpected SSH2_MSG_UNIMPLEMENTED packet. )

 

 

아래와 같이 Putty -> 설정에서 Diffie-Hellman group 14 항목을 맨 위로 올린다.

 

 

 

 

 

 

 

 

 

 

도움받은 사이트 :

 - 행복한 코딩세상 (http://downman.tistory.com/231)

 - Stack OverFlow (https://stackoverflow.com/questions/8512958/is-there-a-windows-variant-of-strsep)

 

 

아래와 같이 콤마로 구분되어있는 문자열은 strtok() 함수를 사용하여 쉽게 문자열을 구분할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdio>
#include <cstring>
 
int main()
{
        char szText[256] ;
        char *pSep ;
 
        strcpy(szText, "name,age,address") ;
 
        pSep = strtok(szText, ",") ;
        printf("1 : %s\n", pSep) ;
 
        pSep = strtok(NULL, ",") ;
        printf("2 : %s\n", pSep) ;
 
        pSep = strtok(NULL, ",") ;
        printf("3 : %s\n", pSep) ;
 
        return 1 ;
}

 

만약 아래와 같이 내용없는 토큰이 연달아 나타난다면,

"name,age,,,,address"

안타깝게도 strtok 는 내용없는 부분을 그냥 무시해버린다.

 

무시하지 않도록 하기 위해 strsep() 함수를 쓸 수 있다.

 

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
#include <cstdio>
#include <cstring>
 
int main()
{
        char szText[256] ;
        char *pSep ;
        char *pText;
 
        strcpy(szText, "name,age,,,,address") ;
 
        pText = szText ;
        pSep = strsep(&pText, ",") ;
        printf("pSep : %s\n", pSep) ;
 
        pSep = strsep(&pText, ",") ;
        printf("pSep : %s\n", pSep) ;
 
        pSep = strsep(&pText, ",") ;
        pSep = strsep(&pText, ",") ;
        pSep = strsep(&pText, ",") ;
 
        pSep = strsep(&pText, ",") ;
        printf("pSep : %s\n", pSep) ;
 
        return 1 ;
}

내용없는 token 을 skip 하기 위해 strsep 함수를 그냥 세번 호출한 부분을 볼 수 있다.

 

문제는 이 함수는 Linux 에서 제공을 하기때문에 Visual C++ 개발환경에선 strsep() 함수를 제공하지 않는다.

 

이에 아래와 같이 strsep 함수를 직접 만들어 쓰면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char* mystrsep(char** stringp, const char* delim)
{
        char* start = *stringp;
        char* p;
 
        p = (start != NULL) ? strpbrk(start, delim) : NULL;
 
        if (p == NULL)
        {
                *stringp = NULL;
        }
        else
        {
                *p = '\0';
                *stringp = p + 1;
        }
 
        return start;
}

 

(본 글은 Zebra 사의 Zebra Programming Guide 문서를 가지고 작성하였습니다.)

 

테스트 프린터 : ZM400, ZT410

 

본 글은 ZPL 에서 영어 이외의 글자. 예를 들어 스페인어 독일어, 체코어 등을 표시하는 법을 다룹니다.

ë, ß, Ä, é

뭐, 이런 글자들입니다.

 

예를 들어, 프랑스어 Référence 를 출력하는 코드는 아래와 같습니다.

^XA
^CI0
^FO80,70 ^A0N,30,30
^FH^FD R_82f_82rence SCF^FS
^XZ

 

위 문서에 보면 프랑스어는 Zebra Code Page 850 에 정의되어 있습니다.

그리고 é 는 Hex값으로 82 정의되어 있습니다.

 

 

 

 

위와 같이 특수문자는 정의된 Hex 값 앞에 _ 를 붙여 표시할 수 있습니다.

 

CI0 는 Zebra Code page 850 을 사용하겠다는 의미입니다. (문서의 ^CI 참조)

 

 

만약 체코어를 출력하게되면 어떻게 해야할까요?

Čeština 와 같이 말입니다.

 

위 Zebra Code page 850 에선 Č, š 와 같은 문자를 찾을 수 없습니다.

이 문자는 Zebra Code page 1250 에 정의되어 있습니다.

 

 

 

 

프랑스어와 같이 출력하면 아래와 같은 코드가 됩니다.

이 때 주의할 점은 ^CI31 로 값이 주어집니다.

이는 위 문서에 의해, Zebra Code page 1250 을 사용하기 위해선 CI31 로 세팅하라고 명시되어 잇습니다.

 

 ^XA
^CI31
^FO80,70 ^A0N,30,30
^FH^FD _c8e_9atina SCF^FS
^XZ

 

이렇게 간단히 특수문자를 출력하는 방법을 알아보았습니다.

도움받은 사이트 : https://stackoverflow.com/questions/33615048/what-zpl-codes-could-affect-the-start-position-of-a-qrcode

 

프린터 : ZM400, ZT410

 

아래는 간단한 QR Code 를 출력하는 ZPL 코드입니다.

 

^XA

^FO 0,0

^BQ N,2,15
^FDMA,hahaite^FS

^XZ

그런데 어쩔 때 보면 위와 같이 좌표를 0,0으로 주었는데도 QR Code 상단에 여백이 생기는 경우가 발생합니다.

예상 위치보다 더 아래에 출력된다는거죠.

 

웃긴게 이게 막 왔다갔다 하더라는거죠. 어떤날은 여백이 요만큼인데 어떤날은 여백이 이만큼인...

 

이래저래 찾아보니 이전에 출력한 바코드가 영향을 주는 듯 하더군요.

 

위 링크 사이트를 참고하여, QRCode 출력 전 dummy 바코드 하나 추가하니 해결되었습니다.

 

^XA

^BY,,1

^FO 0,0

^BQ N,2,15
^FDMA,hahaite^FS

^XZ 

 

 

 

공유기에 내 PC 와 잉여 노트북에 MariaDB 설치함.

C++ 기반 MariaDB API 를 포팅하고 for 문을 약 25만번 돌면서

select 를 날려 값이 중복되는지 체크하는, 복잡하지 않은 테스트였다.

 

노트북에서 테스트가 잘 되어 회사 서버(Ubunru) 에 설치하여 똑같이 테스트를 진행하는데

Lost connection to MySQL server during query.

가 뜨는 것이었다.

 

구글링해보니 이래저래 많은 해결책이 있어 금방 해결하겠다 싶었는데, 뭘 해도 해결이 안됨.

정말, 검색해서 나오는 건 다 해본듯 하다. 심지어 OS 문제인가 싶어 VirtualBox에 Ubuntu 14, 16도 설치해보고,

MariaDB Upgrade, Downgrade 도 해보고, 쿼리 사이에 Sleep 도 줘보고,

심지어 DB 연결 -> 쿼리 하나 전송 -> 연결해제 -> DB 연결 -> 쿼리 하나 전송 -> 연결 해제~~

이런 식으로도 테스트를 해 보았지만 위 증상은 여전했다.

 

♣ Error Log 체크

그러다 MariaDB 의 에러로그를 봤다.

[Warning] Aborted connection 16 to db: 'base_station' user: 'mesteam' host: '192.168.10.25' (Got an error reading communication packets).

 

혹시나 하고 위 error 내역으로 구글링을 진행하고 아래 사이트까지 가게 됨.

https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/

그야말로 이 이슈에 대해 할 수 있는 건 다 정리해 놓은 듯 했다.

그 중 tcpdump 를 떠 보라는 내용이 보여 MariaDB Server 에서 TCP Dump 를 실행하고 쿼리를 날려보았다.

 $ sudo tcpdump port 3306

 

♣ TCP Dump

그렇게, 양단이 쿼리와 ACK 를 다다다~ 주고 받다가, 위 증상이 나타났을 때 어~! 뭔가 이상함을 발견함.

14:16:57.598731 IP 192.168.10.25.51060 > 192.168.109.5.mysql: Flags [P.], seq 1860445:1860525, ack 3837097, win 251, length 80
14:16:57.598987 IP 192.168.109.5.mysql > 192.168.10.25.51060: Flags [P.], seq 3837097:3837262, ack 1860525, win 237, length 165
14:16:57.599944 IP 192.168.10.25.51060 > 192.168.109.5.mysql: Flags [P.], seq 1860525:1860605, ack 3837262, win 256, length 80
14:16:57.600200 IP 192.168.109.5.mysql > 192.168.10.25.51060: Flags [P.], seq 3837262:3837427, ack 1860605, win 237, length 165
14:17:49.661117 IP 192.168.109.5.mysql > 192.168.10.25.51060: Flags [P.], seq 9712582:9712747, ack 4709245, win 237, length 165
14:17:49.661515 IP 192.168.109.5.mysql > 192.168.253.200.51060: Flags [P.], seq 2639052253:2639052418, ack 1996360229, win 237, length 165
14:17:52.424828 IP 192.168.10.25.51060 > 192.168.109.5.mysql: Flags [P.], seq 4709165:4709245, ack 9712582, win 254, length 80
14:17:52.424854 IP 192.168.109.5.mysql > 192.168.10.25.51060: Flags [.], ack 4709245, win 237, options [nop,nop,sack 1 {4709165:4709245}], length 0
14:17:52.425088 IP 192.168.109.5.mysql > 192.168.253.200.51060: Flags [.], ack 1, win 237, options [nop,nop,sack 1 {4294967217:1}], length 0
14:17:56.205151 IP 192.168.109.5.mysql > 192.168.10.25.51060: Flags [P.], seq 9712582:9712747, ack 4709245, win 237, length 165
14:17:56.205610 IP 192.168.109.5.mysql > 192.168.253.200.51060: Flags [P.], seq 0:165, ack 1, win 237, length 165
14:18:02.025159 IP 192.168.10.25.51060 > 192.168.109.5.mysql: Flags [R.], seq 4709245, ack 9712582, win 0, length 0
 

192.168.109.5 : DB Server

192.168.10.25 : 회사에서 부여받은 내 IP -> 공유기에 세팅해서 사용함.

192.168.253.200 : 공유기에서 DHCP 로 할당한, 내 PC 의 IP.

 

즉 어느 시점에서 DB Server 가 공유기가 아닌, 내 PC 로 패킷을 날리기 시작한 것이다.

이것은, 공유기 문제?

 

그래서 공유기를 빼고 라인을 직접 내 PC 에 연결하여 테스트를 진행해 보았더니, 잘된다.

하아~~

 

공유기 설정문제인지, 공유기 자체 버그인지는 아직 모른다.

공유기를 다른 회사 제품으로 바꾸어 테스트해보니 이상없이 잘 돌아간다.

하~ 회사 이름을 밝힐 수도 없고... 일단 공유기를 교체하고 진행하자.

 

 

아내 폰으로 보낸 딸의 카톡에 두번정도 깜빡 속았다.

오늘도 속을 뻔 했다.

​그러다 패턴 발견 ㅋㅋ

띄어쓰기가 없다. 이젠 안속는다 이뇬아~ ㅋㅋ



'상사꽃 > 때로는' 카테고리의 다른 글

안산 다문화 거리  (0) 2021.06.20
김연아의 성화 점화를 반대했다.  (0) 2018.02.25
공단오거리  (0) 2018.01.03
청춘들의 민중가요 뒷풀이 노래  (0) 2017.12.22
억겁의 5년  (0) 2017.05.09

폐막식 중인데 개막식 이벤트를 쓰고 있네.ㅋ


나는 김연아의 성화 점화를 반대했다.

무언가, 너무 뻔한 스토리같다는 생각이 들었기 때문이다.


와~ 그런데, 경기장 꼭대기에 미니 스케이트장(?)을 만들어 놓고

왜 김연아가 성화 점화를 해야하는지 증명하였다.


특히 휙~ 타다가 촤악~ 했더니 바닥에 생긴 아름다운 브레이크선. 아흑~

전설의 성화 점화로 오래오래 남았으면 좋겠다.


'상사꽃 > 때로는' 카테고리의 다른 글

안산 다문화 거리  (0) 2021.06.20
딸의 카톡  (0) 2018.03.04
공단오거리  (0) 2018.01.03
청춘들의 민중가요 뒷풀이 노래  (0) 2017.12.22
억겁의 5년  (0) 2017.05.09

​밤 11시, 적막 가득한 공단오거리.

승객없는 버스는 서둘러 기지로 가고 있고
할일 다 한 신호등은 노란불만 껌뻑이고 있다.

한기는 발목부터 휘감으며 올라오고 
샤니 공장의 빵굽는 냄새는 온 공단에 가득하다.

달달한 냄새에 허기가 진다.





'상사꽃 > 때로는' 카테고리의 다른 글

딸의 카톡  (0) 2018.03.04
김연아의 성화 점화를 반대했다.  (0) 2018.02.25
청춘들의 민중가요 뒷풀이 노래  (0) 2017.12.22
억겁의 5년  (0) 2017.05.09
PARK OUT  (0) 2017.04.12

도움받은 사이트 :

 - http://bitsoul.tistory.com/m/150

 - https://bash.cyberciti.biz/guide/Logical_Not_!

 

리눅스에서 개발하다보면 남의 코드를 받았을 때 한글이 다 깨지는 증상이 있다.

 

이는 저쪽 개발자가 source insight 로 개발한 경우가 대부분이다.

source insight 는 UTF-8 을 지원하지 않아 한글을 입력하면 euc-kr 로 저장된다.

 

이를 리눅스환경에서 열면 한글이 모두 깨져보이게 된다. 

(정확히 표현하면 charset이 euc-kr 이 아닌 경우)

 

검색해보니 어떤 중국인이 source insight UTF-8 플러그인을 개발한 것 같다.

사족인데, source insight 쓸거면 호환성을 위해 UTF-8 플러그인을 설치했으면 한다.

 

아래는 euc-kr 방식의 파일을 리눅스에서 UTF-8 방식으로 전환하는 방법이다.

 

 $ locale

locale 명령어로 linux 로 저장되는 파일 방식을 확인할 수 있다.

내가 문서나 코드를 작성하고 저장했을 때, UTF-8 로 저장되는지 확인해 본다.

 

 $ file -i test.c

test.c 란 파일의 charset 을 확인한다. ISO8859-1 로 나오면 euc-kr로 여겨도... 되나?

한글이 깨진 파일을 위 명령어로 확인해 보면 charset=ISO8859-1 로 나온다.

 

 $ iconv -c -f euc-kr -t utf-8 test.c > test_utf8.c

test.c 의 charset을 UTF-8 로 변경하여 test_utf8.c 란 파일로 저장한다.

이 후, test_utf8.c 를 test.c 로 복사하여 원 코드를 변경할 수 있다.

 

참고로, 아래와 test.c > test.c 같이 파일이름을 같게 하면 안된다. 주의하자.

 $ iconv -c -f euc-kr -t utf-8 test.c > test.c

 

위 번거로움을 아래와 같이 shell script 하나 작성해서 편하게 utf-8로 변경할 수 있겠다.

 $ touch convUTF8.sh

 $ chmod +x convUTF8.sh

 $ vi convUTF8.sh

 

if [ -z $1 ]

then
        echo "Please input file to convert."
        exit
fi

 

if [ ! -f $1 ]
then
        echo "Cannot find the file - $1"
        exit
fi

 

cp $1 $1.org
iconv -c -f euc-kr -t utf-8 $1 > $1.utf8
cp $1.utf8 $1
rm $1
echo "Converted file $1"

 

 

이 후,

 $ convUTF8.sh test.c

하면 test.c 의 charset 을 UTF-8 로 복사하며,

원래 파일은 test.c.org 로 백업한다.

 

 

12월 9일 청춘들의 민중가요 뒷풀이에서 다같이 노래한곡~

 

 

 

 

 

 

 

 

'상사꽃 > 때로는' 카테고리의 다른 글

김연아의 성화 점화를 반대했다.  (0) 2018.02.25
공단오거리  (0) 2018.01.03
억겁의 5년  (0) 2017.05.09
PARK OUT  (0) 2017.04.12
오랜만에...  (0) 2017.01.19

예전 싸이월드 블로그에 작성한 글을 티스토리로 옮김.

싸이블로그 링크 : http://cy.cyworld.com/home/21147242/post/4EE70E1794D5739A07C68401

원문 작성일 : 2011년 12월 23일

 

================================================================

도움 받은 사이트 : http://apollo89.tistory.com/173
프로젝트 진행중에 컴파일을 하면
driver 하위 디렉토리들이 자기 밑에 objs 라는 디렉토리를 수십개 생성해버림.


drvier/audio/objs
drvier/audio/src/objs
drvier/video/objs
drvier/video/src/objs


갯수가 적으면 그려려니 하겠는데, 수십개가 뜨다보니
svn st 하면


? drvier/audio/objs
? drvier/audio/src/objs
? drvier/video/objs
? drvier/video/src/objs
 .............


해서 화면을 뒤덮어버림. ;;;;;;
전에 선임이 svn ignore 를 쓰던 기억이 떠올라 찾아봄.
별 생각없이 덤볐는데 의외로 사용법이 까칠하여 이것저것 정리해 봄.
svn propset (또는 svn ps ) 를 이용하는 방법과,
svn propedit (또는 svn pe ) 를 이용하는 방법이 있다.


♣ svn propset 성공 사례 - 1

$ svn propset svn:ignore objs ./driver/audio/
$ svn propset svn:ignore objs ./driver/audio/src/
$ svn propset svn:ignore objs ./driver/video/
$ svn propset svn:ignore objs ./driver/video/src/
$ svn st


이러고 제대로 되었는지 확인.


♣ svn propset 실패 사례 - 1
$ svn propset svn:ignore


./driver/audio/objs ./

 


♣ svn propset 실패 사례 - 2
$ svn propset svn:ignore


objs objs2


./driver/audio/src/


// 한번에 하나씩


♣ svn propset 실패 사례 - 3
$ svn propset svn:ignore objs ./ -R

// Recursive 안됨. ;;;


♣ svn propedit 성공 사례 - 1

$ svn propedit svn:ignore driver/audio/


(편집창 뜨면)
objs
(저장하고 나옴.)
이렇게 나머지 세 디렉토리를 일일이 해 주어야 함.


♣ svn propedit 실패 사례

$ svn propedit svn:ignore ./
(편집창 뜨면)


driver/audio/
driver/audio/src/
driver/video/
driver/video/src/


(저장하고 나옴.)


(이렇게 하니 안됨)


일단 이렇게 해서 수십개의 objs 디렉토리를 일일이 svn propset svn:ignore 명령어로
무시시켜버림.
svn st 하니 깔끔해서 좋다.
찜찜한게, 이렇게 노가다를 해야하는건가? 뭔가 좋은 방법이 숨어있을 것 같은 느낌이...

 

 

Vector의 2차원 배열 표시 도움받은 곳 : http://sosal.kr/524

 

오일러 프로젝트 풀다가 아래와 같은 구조를 생성할 일이 있어

짜긴 했는데, 이런 구조를 뭐라 하는지 모르겠네요.

 

일단 TriangleTree 라고 명하고 클래스를 만들어보았습니다.

- triangleTree.h

- triangleTree.cpp

 

그리고 main.cpp

에서 함수 호출의 예를 볼 수 있습니다.

 

 

 

 

triangleTree.h

 

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
#ifndef _TRIANGLETREE_H_
#define _TRIANGLETREE_H_
 
#include <vector>
 
class CTriangleTree
{
public :
        int init(int width) ;
        int getNext(int* pList) ;
        int destroy() ;
 
private :
        int loop() ;
 
public :
 
private :
        int m_width ;
        int m_max ;
 
        std::vector<std::vector<int> >  m_data ;
        std::vector<int>        m_direct ;
        std::vector<int>        m_value ;
 
 
        int m_status ;
        int m_row ;
        int m_col ;
 
};
 
#endif
 

 

triangleTree.cpp

 

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 "triangleTree.h"
 
#include <cstdio>
 
#define LEFT    0x01
#define RIGHT   0x02
 
#define MOVE_FIRST_CHILD        0X04
#define MOVE_SECOND_CHILD       0X05
#define MOVE_PARENT             0X06
 
using namespace std ;
 
int CTriangleTree::init(int width)
{
        m_max = width ;
 
        m_status = MOVE_FIRST_CHILD ;
        m_row = 0 ;
        m_col = 0 ;
 
        m_data.clear() ;
        m_direct.clear() ;
        m_value.clear() ;
 
        m_direct.assign(width, LEFT) ;
 
        m_data.assign(width, vector<int>(width, 0)) ;
 
        for(int ii = 0; ii < m_max; ii++)
        {
                for(int jj = 0; jj <= ii; jj++)
                        m_data[ii][jj] = jj ;
        }
 
        m_value.assign(width, 0) ;
 
        return 1 ;
}
 
int CTriangleTree::getNext(int* pList)
{
        if(m_row  == m_max-1 && m_col == m_max-1)
                return 0 ;
 
        int ii ;
        int flagBreak = 0 ;
 
        while(1)
        {
                if(flagBreak)
                        break ;
 
                switch(m_status)
                {
                case MOVE_FIRST_CHILD :
                        m_row++ ;
                        m_value[m_row] = m_data[m_row][m_col] ;
                        m_direct[m_row - 1] = LEFT ;
 
                        m_status = (m_row < m_max-1) ? MOVE_FIRST_CHILD : MOVE_SECOND_CHILD ;
 
                        if(m_row == m_max-1)
                        {
                                for(ii = 0; ii <= m_row ; ii++)
                                        pList[ii] = m_value[ii] ;
                                return 1 ;
                        }
                        break ;
 
                case MOVE_SECOND_CHILD :
                        m_col++ ;
                        m_value[m_row] = m_data[m_row][m_col] ;
 
                        m_direct[m_row - 1] = RIGHT ;
                        m_status = (m_row < m_max-1) ?  MOVE_FIRST_CHILD : MOVE_PARENT ;
 
                        if(m_row == m_max-1)
                        {
                                for(ii = 0; ii <= m_row ; ii++)
                                        pList[ii] = m_value[ii] ;
                                return 1 ;
                        }
                        break ;
                case MOVE_PARENT :
                        if(m_direct[m_row-1] == RIGHT)
                                m_col-- ;
                        m_row-- ;
 
                        if(m_row == 0)
                        {
                                m_status = MOVE_SECOND_CHILD ;
                                m_row++ ;
                                break ;
                        }
 
                        m_status = (m_direct[m_row-1] == LEFT) ?  MOVE_SECOND_CHILD : MOVE_PARENT ;
                        break ;
                }
        }
 
        return 0 ;
}
 
int CTriangleTree::destroy()
{
        m_data.clear() ;
        m_direct.clear() ;
        m_value.clear() ;
 
        return 1 ;
}
 

 

main.cpp

 

 

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
#include "triangleTree.h"
 
#include <cstdio>
 
using namespace std ;
 
int main()
{
        CTriangleTree triTree ;
 
        const int MAX = 5 ;
 
        triTree.init(MAX) ;
        int value[MAX] ;
 
        while(1)
        {
                if(!triTree.getNext(value))
                        break ;
 
                for(int ii = 0; ii < MAX; ii++)
                        printf("%d ", value[ii]) ;
                printf("\n") ;
 
        }
 
        return 1 ;
}
 

 

조합을 구하려다 한참을 삽질하고,

결국 로제타 코드에서 큰 도움을 받았다.

( https://rosettacode.org/wiki/Combinations#C.2B.2B )

 

어찌나 쉽고 심플하게 짜놨는지... 허망~

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <algorithm>
#include <iostream>
#include <string>
 
void comb(int N, int K)
{
    std::string bitmask(K, 1); // K leading 1's
    bitmask.resize(N, 0); // N-K trailing 0's
 
    // print integers and permute bitmask
    do {
        for (int i = 0; i < N; ++i) // [0..N-1] integers
        {
            if (bitmask[i]) std::cout << " " << i;
        }
        std::cout << std::endl;
    } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
 
int main()
{
    comb(5, 3);
}
 

 

위 코드를 참고하여 써먹기 쉽게 아래처럼 클래스화 시켜 보았다.

 

 

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
#include <cstdio>
 
#include <vector>
#include <algorithm>
#include <string>
 
 
using namespace std ;
 
class CCombination
{
public :
        CCombination(vector<int>* vecInt, int r) ;
 
        int getNext(vector<int>* vecCombi) ;
 
private :
        string m_bitmask ;
        vector<int>* m_vecInt ;
 
};
 
CCombination::CCombination(vector<int>* vecInt, int r)
{
        m_vecInt = vecInt ;
 
        m_bitmask.clear() ;
        m_bitmask.resize(r, 1) ;
        m_bitmask.resize(vecInt->size(), 0) ;
}
 
 
int CCombination::getNext(vector<int>* vecCombi)
{
        vecCombi->clear() ;
 
        int size = m_bitmask.size() ;
 
        for(int ii = 0; ii < size; ii++)
        {
                if(m_bitmask[ii])
                        vecCombi->push_back((*m_vecInt)[ii]) ;
        }
 
        if(!prev_permutation(m_bitmask.begin(), m_bitmask.end()))
                return 0 ;
 
        return 1 ;
}
 
int main()
{
        vector<int> vecInt ;
        vector<int> vecCombi ;
 
        int n = 6 ;
        int r = 4 ;
 
        for(int ii = 1; ii <= n; ii++)
                vecInt.push_back(ii) ;
 
        CCombination combination(&vecInt, r) ;
 
        int flagBreak ;
 
        while(1)
        {
                flagBreak = combination.getNext(&vecCombi) ;
 
                for(int ii = 0; ii < r; ii++)
                        printf("%d ", vecCombi[ii]) ;
                printf("\n") ;
 
                if(!flagBreak)
                        break ;
        }
 
        return 1 ;
}
 
 
 

뭔가 썩 마음에 들진 않는데 딱히 개선안이 떠오르지 않는다. 허망함 때문인가? ㅋㅋ

시간이 지나면 떠오를 때가 있겠지.

+ Recent posts