touch

touch는 파일의 날짜시간정보를 변경하는 명령어이다. 즉 아무런 옵션없이 사용하면 서버의 현재시간으로 파일의 최근사용한 시간(access time)과 최근변경 시간(modification time)을 변경한다. 만약 특정옵션이 사용되지 않는다면 파일의 크기가 0인 빈 파일을 생성한다. -t 라는 옵션을 사용하면 서버의 현재시간이 아닌 지정된 시간으로 파일의 날짜시간정보를 변경한다.

touch [옵션] 파일명

빈 파일 생성

BASH
touch newfile

현재시간으로 파일 날짜정보 변경

BASH
touch -c newfile

파일의 날짜정보를 마음대로 변경(YYYYMMDDhhmm 형식)

BASH
touch -t 201306141200 newfile  

지정한 파일의 날짜시간정보를 지정한 다른 파일의 날짜시간정보와 동일하게 변경(newfile을 oldfile의 날짜정보와 같게 변경)

BASH
touch -r oldfile newfile



 

블로그 이미지

낭만가을

,

서울그린치과(양심치과) 강창용 원장님의 과잉진료 피하는 방법을 소개합니다.




사람이 아프면 병원에 가야합니다.
그리고 의사에게 진료를 받고 치료를 하기 위해서는 비용을 지불해야 하죠.

대부분의 사람들은 의학지식이 없기 때문에 의사의 진료를 맹신할 수 밖에 없고 고가의 비용이 청구되더라도 받아들일 수 밖에 없습니다.

최근들어 병원의 경쟁이 가속화됨에 따라 수익성이 저하된 일부 의사는 이런 점을 노리고 있습니다.

의사는 의학지식이 전무한 환자의 허점을 노려 하지 않아도 될 과잉진료를 하고 그 치료를 통해 부당한 수익을 거둡니다.

특히나 치과에서 이런 현상이 두드러지고 있고 보다 못한 강창용원장님은 직접 나서 치과의사들의 과잉진료 행태를 고발하게 됩니다.


그럼 어떤 식으로 과잉진료를 하고 환자들에게 눈탱이를 치는지 알아보겠습니다.



양심치과 강창용 원장의 금니3개 과잉진료하는 치과사기 수법 
https://www.youtube.com/watch?v=6guMz9zcRl8


양심치과 강창용 원장 - 치과 의사들이 충치로 사기치는 법
https://www.youtube.com/watch?v=WMDV26_h63w


양심치과 강창용 원장 - 20대 여성 앞니에 금간걸로 겁주고 과잉치료비 요구하는 의사들
https://www.youtube.com/watch?v=0phu5r2uj28



양심치과 강창용 원장의 치아사이의 충치 이야기
https://www.youtube.com/watch?v=WQcgqWGKwOA



양심치과 강창용 원장 - 충치 그려서 사기치는 치과들 피하기
https://www.youtube.com/watch?v=GyvqVma3Cuk


양심치과 강창용 원장 - 사랑니 언제 빼야 할까?
https://www.youtube.com/watch?v=mwQ4ewk1l_I



양심치과 강창용 원장 - 치과 의사들이 환자 눈탱이 치는 수법과 대응 방법
https://www.youtube.com/watch?v=MR3H0b6I2Js



양심치과 강창용원장의 신경치료 피하는 충치제거법!
https://www.youtube.com/watch?v=HlyAH7n6lMc



양심치과 강창용 원장의 눈물어린 호소!
https://www.youtube.com/watch?v=jYW4Qtfv7nw



블로그 이미지

낭만가을

,

선대인경제연구소장은 예전부터 부동산 가격상승으로 인한 우려를 계속해서 나타냈습니다.
이런 모습으로 많은 분들이 선대인소장은 하락론자다, 돌팔이다며 그 때 당시 집을 사지 않았던 분들의 원성도 자자합니다.

하지만 개인적으로 예나 지금이나 천정부지로 오르는 부동산 가격상승은 비정상적이라 생각하고 이명박, 박근혜의 경제정책의 영향을 받았기 때문에 요번 문재인 정부는 과거와는 다른 양상으로 부동산 경기가 흐를 수 있다고 생각합니다.



다음은 선대인경제연구소장의 문재인 정부의 부동산 정책에 대


심도있는 분석과 가격전망에 대한 내용입니다.




선대인이 분석하는 문재인 정부의 부동산 정책과 전망 - 1 


https://www.youtube.com/watch?v=Mgzl06vo-eM



선대인이 분석하는 문재인 정부의 부동산 정책과 전망 - 2
https://www.youtube.com/watch?v=R9_m29cH8O8

이 밖에도 부동산 시장의 종합적인 문제점을 꼬집어보는 영상입니다.
부동산에 투자하실 분들은 꼭 한번 봐주시길 바랍니다.


 
한민국 부동산은 어디로 갈 것인가 - 부동산 전망 알아보기 
https://www.youtube.com/watch?v=MIHqJKPVXmI



이 밖에 다양한 경제관련 동영상을 보고 싶으시면 아래 링크를 클릭해주세요.
https://www.youtube.com/playlist?list=PLHjMK_EwvmJ7tx_eQN3UYfvMXUeMEHBwS



 

블로그 이미지

낭만가을

,

시계를 비싸게 살 이유가 없습니다!
저렴하고 다양한 기능이 있는 카시오라면 말이지요.

3만원짜리 카시오 메탈시계라면 간지나니까요.

[기능]

백라이트
알람
시보
24시간제
스탑워치
생활방수


간지나는 3만원짜리 가성비 끝판왕 메탈 시계 리뷰 - 카시오 A168WA-1WDF
https://www.youtube.com/watch?v=OQo17kC3_2k

이 시계를 구입한 이유는 저렴하기 때문이었습니다.
또한 메탈시계였기 때문이죠.

다양한 기능이 있는 건 덤이였고요

위 영상을 보시면 아시겠지만 마감도 굉장히 훌륭합니다.
버튼도 유격이 없고 금속재질로 단단하게 눌립니다.

결코 3만원짜리 시계로 보이지 않습니다.
(실제로 주변분들도 그렇다고 합니다.)

이 시계에서 놀랐던 것은 백라이트와 시계줄입니다.

저렴한 시계의 백라이트는 액정의 전체화면을 골고루 비춰주지 못했습니다.
하지만 이 시계는 백라이트가 완벽하게 전체적으로 밝혀주더군요.

또 한번 놀랬던 것은 시계줄입니다.
보통 시계줄을 자신의 손목에 맞게 줄이려면 전문 공구가 있어야 하지만 이 시계는 필요가 없습니다.

이 시계는 굉장히 가볍고 부담 없는 가격이라 출퇴근에 매일 착용하고 있고 부딪히고 기스가 나더라도 걱정이 들지 않습니다 ㅎㅎ

저는 이 시계로 인해 카시오의 매력에 빠졌고 다음 제품으로 터프솔라 기능이 있는 카시오 시계를 구입해 보려고 합니다.



 

블로그 이미지

낭만가을

,

SI(System Integration)

- 시스템 통합. 대형기관에서 사용하는 업무들을 전산적으로 통합하는 작업. 흔하게는 엔터프라이즈 시스템이라고 부르고. 공공기관, 대기업, 금융권 등의 업무들을 전산화 또는 기존의 시스템들을 통합하여 이전보다 나은 업무프로세스 및 성능개선을 통해 공공 또는 기업의 이익을 추구하는 작업.

이라고 말하고 노가다라고 부르면 적당함.


SM(System Maintenance)

- 보통 SI프로젝트가 끝나면 그 시스템에 대한 유지보수를 말함. 어디서는 Maintenance가 아니라 Management라고 부르는 쪽도 있음.


BP(Business Process) 서버?

- 몇번 듣다보니 뭐하는 건지는 알았는데 뭔 약자인지 한참 찾은 용어. 접속서버(중계서버)라는 말로도 사용하고 보통 클라이언트가 엔터프라이즈시스템에 직접 연결되는 것이 아니라 중간에 중계서버를 둔다.

실제 클라이언트와의 커넥션을 담당하며 보안적인 측면에서 망을 분리하는 효과 뿐만 아니라 L4장비와 함께 로드밸런싱을 담당하기도 함.




CDC(Change Data Capture) 

- 말 그대로 변경된 데이터에 대한 이미지를 생성. 어떤 데이터가 어떻게 변경되었다라는 history를 가질 뿐만 아니라 백업용도로 미러링기능을 가지고 있음.

대부분의 솔루션들이 DB의 아카이브모드를 사용하는 듯.




BCV(Business Continuance Volume)

보통 백업용도로 사용하며 디스크의 볼륨단위를 그대로 미러링한 카피본이라고 보면 된다.

데이터나 시스템의 특성에 따라 사용방법이 조금씩은 다를 수 있다. 순간처리건이 많은 경우는 단순히 백업용도로 사용할 수 도 있고. 시스템 장애시 백업받은 디스크 볼륨을 그대로 복구처리해 장애에 대처하는 경우도 있다.

일반적으로 백업을 위해서 따로 작업을 해두는게 아니라 항상 마스터 볼륨과 Sync를 맞추고 있다가 백업순간 Sync를 끊는다.


On Demand Batch

- 배치작업을 스케쥴링에 의해 실행하는 것이 아니라 사용자가 요청시에만 동작하는 배치작업.

사용자의 요건에 따라 발생된 대량처리건을 처리하기 위해 사용.


CenterCut

- On Demand Batch 와 마찬가지로 사용자에 요건에 따라 발생된 대량처리건을 처리하는 아키텍쳐

On Demand Batch와 다른 점은 배치프로그램이 동작하는 것이 아니라 각 처리건을 온라인서비스로 처리하는 것이 차이점이다.

배치를 추가로 만들지 않고 기존의 서비스로 처리하는 것과 부하에 대한 유량제어로 시스템이 부하를 받지 않도록 처리가 가능한 장점이지만 센터컷 자체 아키텍쳐 구축이 쉽지 않다. 센터컷 아키텍쳐는 유량제어, 각 처리건에 대한 결과 및 에러시 복구 및 장애 대책을 가지고 있어야 한다.

대량의 데이터를 개별서비스단위로 쪼개는 작업도 만만치 않다.

* OnDemandBatch하고 CenterCut 기술들이 자바프레임워크를 쓰는 동네에서는 어떻게 보이는지 잘 모르겠다.


DryRun

- 시운전, 리허설 정도로 해석하면 될 듯.


RFI(Request For Information)

- 보통 정보요청서로 부르며 아래 나오는 RFP 전에 작성된다. 프로젝트를 진행하려는 측에서 내부적인 기준으로 선정한 업체들에게 우리 이러이러한 프로젝트를 하려고 하는데 정보 좀 보내달라. 뭐 이런 용도의 문서다. 프로젝트를 진행하려는 측에서는 프로젝트에 적용될 기술이나 업계동향, 프로젝트의 진행방식 등 시스템 구축에 필요한 컨설팅단계를 진행한다. 주로 컨설팅 업체는 RFI 작성시작부터 참여하게 되며, RFI를 받은 업체들도 이때부터 프로젝트 수주에 대한 본격적인 작업에 돌입한다.


RFP(Request For Proposal)

- 프로젝트를 진행하려는 측에서 내부적인 기준으로 선정한 업체에 RFI를 보내면 각 업체들은 해당 프로젝트 성격에 맞게 우리는 이러이러하게 프로젝트를 진행하겠다고 자신들의 솔루션과 노하우, 이전 프로젝트 사례등을 담은 RFP를 작성해 제출한다. RFP를 받은 갑은 자 이제 어디까지가 구라고 누가 싸고 어떤게 좋을지 이리 저리 재보고 프로젝트를 수행할 업체를 정한다.


Turn-Key

- 본래는 공장기기설비쪽에서 나온 용어로 알고 있음. 개발완료와 동시에 즉시 가동가능한 상태로  인계할 수 있도록 하나의 주사업자가 모든 공정을 책임지고 처리하는 방식. 


In House 방식

어떤 프로젝트에 대해서 개발을 외주인력이 아닌 내부인력으로만 처리하게 되면 In House라 함.


M/M(Man/Month)

- 프로젝트의 일정을 산정할 때 자주 사용되는 단위. 한사람이 한달간 일할 분량.

이런 계산법이 만능은 아니지만 일정의 공수산정을 위해 이거만큼 수치적으로 간단한 단위는 아직 못봤음.

그래서 아직도 자주 사용됨.

10M/M(1Man * 10Month) = 10M/M(10Man * 1Month)... 수치적으로는 같을진 몰라도 실제로 이런 경우는 없음.




SSO(Single Sign On)

- 한번의 로그인으로 여러 시스템을 이용할 수 있게 해주는 솔루션. 웹기반으로는 세션키를 공유하는 방식으로 일반 서버/클라이언트 모듈에서는 agent를 사용한다. 대기업이나 금융권같은 곳은 사용하는 시스템이 기존의 레거시까지 포함하는 경우 SSO를 통해 한번의 로그인으로 사용자를 인증하고 해당 사용자에게 시스템을 이용가능하게 서비스를 제공한다.



EAM(Extrnet Access Management)

- 어디서는 Enterprise Access Management 라고 부르는 곳도 있고 Extranet Access Management라고 부르는 곳도 있다. 

통합인증, 권한관리 시스템으로 SSO시스템에 권한관리, 자원관리 등이 포함된 개념으로 이해하면 될 듯.


IAM(Identify Access Management)

- EAM이 개별사용자에게 권한부여 하는 방식이 자동화되어 있지 못한 반면 IAM은 이를 자동화 처리가능하게 한 시스템이라 줏어들었음. 포괄적인 개념으로 SSO < EAM < IAM 정도로 생각하면 될듯.(넘 날로 먹나?)




EAI(Enterprise Application Integration)

- 통신프로토콜이나 테이터 타입, OS등 각기 다른 환경에서 동작하는 애플리케이션들에 대해 상호 연동할 수 있는 기능을 제공하는 솔루션. 파일, 온라인서비스, DB등 각기 다른 데이터를 주기적 혹은 준실시간(Defered Onlinle)으로 처리함.

이런 EAI를 사용하는 이유는 각 시스템별로 비지니스적으로 다른 처리를 하고 있지만 각 시스템간에 공통된 영역을 효율적으로 연동하기 위해서 사용함.


MCI(Multi Channel Integration)/MCA(Multi Channel Architecture)

- 채널통합. 기업이나 기관에서 다양한 채널과 통신하는 경우가 많은데 각 채널마다 통신방식이나 전문들이 상이한 경우가 많다. 코어시스템입장에서는 이를 동일한 규격으로 통일할 필요가 있으며 이러한 기능을 제공하는 것이 MCI혹은 MCA 솔루션이다. 

있다보면 간혹 EAI와도 중복되는 개념으로 사용되기도 한다.


FEP(Front-End Processor)

- 원래는 메인프레임의 통신제어를 위한 전용 시스템을 말하는데 현재는 굳이 메인프레임에 국한하고 있지 않은듯 하다. 개인적인 판단으로는 OSI7 Layer에서 세션이나 프리젠테이션 계층까지 담당하는 것으로 보인다. 

보통 기관 대 기관 연결이 FEP로 연결되어 있는 경우가 많다.


ESB(Enterprise Service Bus)

- 통합된 서비스구조를 통해 효율적인 시스템 구축 및 유지보수가 용이한 구조라고 하는데 아직까지 뭐가 ESB다 라고 명확하게 나온걸 본적이 없다.

SOA의 핵심사상중에 하나인데 SOA라는 것 자체도 추상적이고 개념적인 내용들이 더 많은게 아직까지의 현실인듯 하다.

말이야 이렇게 하면 뭐에 좋고 이게 좋고 다 말은 하지만 실제 시스템에서 이런걸 구축하려 하면 배보다 배꼽이 더 커지는 경우도 있다.


SCM(Software Configuration Management)

- 형상관리. 개발을 하다 보면 수백 수천 수만개의 소스와 관련 리소스를 관리하게 된다. 이런 리소스들의 날짜별 시간별 히스토리 및 이전 버전과의 비교, 브랜치 관리, 머징 등을 위한 관리시스템을 형상관리시스템이라고 부른다. CVS, SVN, GIT, Mercurial 같은 툴들이 있으며 엔터프라이즈환경에 맞춘 커스텀 솔루션들도 있다. 오픈소스에서 요즘 GIT가 대세인듯..


SOA(Service Oriented Architecture)

- 서비스지향아키텍쳐. 간단하게 말하면 각 단위작업이 서비스로 이루어진 구조를 말한다. 핵심적인 개념은 각 단위작업이 타 서비스에 영향을 미치지 않고 독립적으로 실행된다는 점과 이런 구조로 인해 서비스의 재사용성이 높다는 것인데. 개인적으로는 SOA라고 해서 다 저런 특징을 가지는 것도 아니고 굳이 SOA가 아니더라도 저런 특징을 가질수 있게 만들 수 있다. 결국은 설계단계에서 개발단계에서 이러이러한 구조로 개발을 해야 효율적이겠다 라고 설계하는 것과 크게 다르지 않은 느낌이 든다.


BPM(Business Process Management)

- 비지니스 프로세스를 개선하기 위한 작업을 뜻한다. 개념적으로 보면 그룹웨어가 BPM의 하위개념? subset 정도 될듯 하다. 보통 기업 또는 기관들이 정해진 업무만 처리하는 것이 대부분이지만 신규시장, 신규사업 등 새로운 업무활동을 위해 새로운 프로세스를 수립하게 되는데 이런 일에 사용되는 것이 BPM이다.


MOM(Message Oriented Middleware)

- 메시지 기반 미들웨어. 메시지를 기반으로 비동기식으로 통신하는 미들웨어이다. 기존의 미들웨어는 클라이언트나 타 시스템과 직접연결되어 데이터를 주고 받은 반면 메시지기반 미들웨어는 내부적인 Message Pool 과 같은 개념의 공간을 두고 통신을 한다. 이러한 개념은 커넥션이 끊기면 통신자체가 중단되는 기존 동기방식의 미들웨어와는 달리 한쪽의 통신이 끊기는 것에 크게 영향을 받지 않는다. 개념상 어떻게 처리하느냐보단 뭘 보내느냐가 초점이 맞춰져있는듯 하다. 솔루션으로는 IBM MQ시리즈, BEA Message Q, J2EE의 JMS 등이 있으며 최근들어 비중이 조금씩 높아지는 추세이다.



EDW(Enterprise Data Warehouse)

- warehouse 란 단어가 창고라는 의미를 가진 것과 같이 EDW 는 데이터의 창고라 할 수 있다. 단순하게 자료를 담는 DB의 레벨을 넘어 유효성있는 정보로 가공하기 위한 또는 가공된 정보가 저장된 공간 및 처리하기 위한 기반 시스템을 말한다.

흔히 원장이라고 불리는 애들은 OLTP성으로 실시간으로 데이터가 저장이 되며 EDW에서는 이렇게 실시간으로 쌓인 정보들을 분석, 가공하여 이를 이용자에게 제공한다. 


CCF(Computer to Computer Facility)

- 말 그대로하면 컴퓨터간의 시설? 설비? 정도로 해석할 수 있는데 간단히 말하면 프로토콜의 한 종류? 아니면 특정업무를 위한 전문집합(message set)로 보면 된다. CCF라는 용어를 쓰는데는 우리나라에서는 예탁결제원, 구글을 뒤져봐도 미국의 예탁기관인 DTC. 이 정도 기관에서만 사용하는 듯 하다.(더 찾아보면 나오겠지만)



ETL(extract, transform, load)

ODS(Operational Data Store)

OLTP OLSP


업무 아키텍처(BA)

데이터 아키텍처(DA)

응용 아키텍처(AA)

기술 아키텍처(TA)

보안 아키텍처(SA)

SRDF(Symmetrix Remote Data Facility)


WBS


BRD : Business Requirement Definition (Document)

  요건정의서. 현업이 작성하고 SI 업체에 넘겨준다.


FS : Funtional Specifications

  기능설계서. 개발에 관련한 각종 문서. DB설계서등을 포함하기도 하며, 개발 완료시점의 예상 화면덤프등을 포함하기도 한다.


SIT : System Interstration Test

  코딩 및 테스트를 포함한 개발 과정을 포함한다.


UAT : User Acceptance Test

  실제 오픈 전 테스트.


MQC : Mecury Quaility Center ( = T/D : Test Direction )

  테스트툴 또는 전체 page 오류구간 정리 검사 (툴을 이용하기도 함) 등을 통해서 최종 품질 검사 작업. (PMO조직의) 비니지스 담당자들이 작업한다.


 

블로그 이미지

낭만가을

,
증권회사의 시스템은 어떻게 구성될까요. 메리츠종금증권의 "MINT" 시스템이 언론에 소개된 것이 있어서 그림을 가져와 봅니다.

(From... CIOCISO매거진)


증권회사 시스템이 플랫폼으로 기능하기 위해서는 외부 시스템과의 연결이 필요합니다. 이 그림에서 우선 생각해볼 수 있는 시스템은 "대고객채널"이라 되어있는 부분입니다. 증권회사에서는 HTS, WTS, MTS 등을 외주 개발을 통해 도입하게 됩니다. 이때 각기 달느 시스템 개발사의 프로토콜을 연결하고 통신 채널을 관리할 필요가 생기게 되는데요. 이때 사용되는 솔루션이 바로 MCI(Multi Channel Integration) 솔루션입니다.

MCI 란 은행 대외계 시스템에서 발전한 개념으로, 은행의 고객 접점이 인터넷 뱅킹, 자동화기기(ATM), 모바일뱅킹, 폰뱅킹 등으로 다양해짐에 따라 각 접점별 채널을 통합해 내부 시스템과 연결하는 게이트웨이 시스템을 말합니다. 은행 공동망, 제휴기관, 금융결제원 등 대외 기관과의 연결 프로토콜이 다양해지다보니 대외 채널을 통합해서 관리할 필요성이 증가했고, 특히 방카슈랑스가 시작되면서 보험사와 은행간의 연결 요구가 발생한 이후부터 적극적으로 도입되었다고 하네요.


증권회사에서도 MCI 는 대고객채널 연결에서 사용되곤 합니다. 영업점 단말, HTS, WTS(Web Trading System), MTS  등과 연결할 때 각 시스템마다 다른 프로토콜이나 채널을 갖게되면 관리가 힘들죠. 

(From... LG CNS 블로그)


MCI 의 기능은 크게 아래와 같습니다.
  • 전문 변환 : 외부 시스템의 전문을 내부 시스템의 전문과 매핑
  • 다양한 통신방식 지원 
  •   - Point to Point, Request/Reply, Store/Forward, Publish/Subscribe 등등..
  • 로드밸런싱, Fail over 및 Flow control
  • 배치잡 처리 및 스케쥴러
  • 보안 : 암복호화를 통한 데이터 보안

MCI 구성은요.
  • 채널 어댑터 : 통신 프로토콜 및 비즈니스 프로토콜 인터페이스 담당
  • 매핑 엔진 : 외부 통신 전문을 해당 업무의 내부 전문으로 변환
  • 매핑 DB : 전문 매핑 테이블
  • Developer Studio : 전문 및 매핑 룰 정의
  • Admin tool : 시스템 관리, fail over 및 모니터링

MCI - TMAX AnyLink

MCI - Mocomsys


블로그 이미지

낭만가을

,

여러 가지 데이터 타입 및 자료구조가 있지만, 알고리즘에 집중하기 위해 정수(int) 배열을 오름차순으로 정렬하는 형식으로 진행하겠습니다. 각각의 정렬 알고리즘은 특정 환경에 에서 최적의 성능을 발휘합니다. 메모리 공간을 적게 쓴다든지, 배열의 길이가 얼마 이하이면 제일 빠르다든지, 이미 정렬된 경우 제일 빠르다든지.... 참고로 알고리즘의 성능은 비교 횟수와 교환횟수, 추가로 사용하는 저장 공간, 초기 정렬 상태 등 에 따라 결정됩니다.

swap 함수

/**
* int 배열에서 2개 원소를 서로 교환합니다.
* @param array 전달받은 배열
* @param fromIdx
* @param targetIdx
*/
void swap(int[] array, int fromIdx, int targetIdx) {
int temp = array[targetIdx]; // 목적지 원소를 임시 저장
array[targetIdx] = array[fromIdx];
array[fromIdx] = temp;
}
view rawswap.java hosted with ❤ by GitHub

Bubble Sort(버블 정렬)

가장 단순한 정렬 알고리즘입니다. 비교하는 과정이 탄산음료를 담은 컵에 두개의 거품(크기가 서로 다른)이 수면 위로 상승하는 과정과 비슷합니다. 두 거품이 상승중에 충돌 하였을 때 큰 거품이 작은 거품보다 먼저 상승하게 됩니다.

void bubbleSort(int[] arr){
for(int i = arr.length - 1; i > 0; i --)// main loop, i 는 (배열의 길이 - 1) 에서 1까지 1씩 감소
for(int j =0; j < i ; j++) // j 는 0부터 i 까지 1씩 증가하며 반복
if(arr[j] > arr[j+1]) swap(arr, j, j+1); // index 가 작은 원소가 클경우 교환
}
view rawbubbleSort.java hosted with ❤ by GitHub

이 알고리즘은 표준 정렬 알고리즘 중에 가장 느립니다. 이유는 데이터의 이동(교환)이 인접한 원소들 사이에서만 일어나기 때문입니다.

{7,4,3,2,1} // 초기

예를 들어 위와 같이 5개의 정수를 가진 배열이 있을때 main loop 각 1회전 할 때 7은 총 4번의 교환(swap)을 통해서 제자리를 찾아갑니다.

{4,7,3,2,1} // 내부 loop 1회전
{4,3,7,2,1} // 내부 loop 2회전
{4,3,2,7,1} // 내부 loop 3회전
{4,3,2,1,7} // 내부 loop 4회전

버블 정렬에 있어서 최선의 경우와 최악의 경우 사이의 유일한 차이는 교환 연산의 실제 수행 횟수입니다. 이미 정렬되어있는 배열인 경우 비교 연산만 일어나고, 교환 연산은 일어나지 않습니다. (최선의 경우)

time : worst O(n^2), best O(n), average O(n^2)

Selection Sort(선택정렬)

버블 정렬보다 약간 더 효율적입니다. 자료의 이동을 최소화하려는 목적으로 만들어져서 자료의 양이 적을 때 아주 좋은 성능을 발휘합니다.

void selectionSort(int[] arr){
for(int i = arr.length - 1; i > 0; i --) {
int maxIndex = 0 ; // 배열 원소중 max 값의 index를 저장할 변수
for(int j = 1; j <= i ; j++)
if(arr[j] > arr[maxIndex]) maxIndex = j;
swap(arr, maxIndex, i);
}
}
view rawselectionSort.java hosted with ❤ by GitHub

main loop의 각 회전마다 정렬되지 않은 원소 중에서 가장 큰 원소를 선택하여 그것을 올바른 위치로 이동시키기 때문입니다. 예를 들어 아래의 배열을 정렬합니다.

{7,4,3,2,1} // 초기
{1,4,3,2,7} // main loop 1회전 후

main loop 가 1회전 하면 7은 가장 오른쪽에 배치됩니다. 이때 교환(Swap) 연산은 1 과 7 사이에 한 번만 실행됩니다. 데이터 이동(교환) 은 선형 시간에 실행되어 버블 정렬보다 빠릅니다.

time : worst O(n^2), best O(n^2), average O(n^2)

Insertion Sort(삽입정렬)

위의 버블, 선택 정렬과 다르게 main loop의 i가 를 점점 증가합니다.

void insertionSort(int[] arr){
for(int i = 1; i < arr.length; i++) {
// i가 0이 아니라 1부터 시작합니다. i가 0인 loop 는 비교할 원소가 없습니다.
int ai = arr[i]; // 정렬된 앞 배열에 삽입될 원소, 위치를 찾을 때까지 임시저장.
int j; // 비교 연산 및 이동 연산을 한 임시 변수
for (j = i; j > 0 && arr[j-1] > ai; j--) // 정렬된 배열에서 ai 보다 큰 값이 나올 때까지 j 감소
arr[j] = arr[j - 1]; // 원소가 한 칸씩 우측으로 이동
arr[j] = ai; // 마지막으로 나온 j에 ai 를 삽입
}
}
view rawinsertionSort.java hosted with ❤ by GitHub

삽입정렬은 데이터 이동 횟수는 버블, 선택정렬에 비교해 많지만 그 정렬보다 느리진 않습니다. 그 이유는 평균적으로 삽입정렬은 비교하는 횟수가 절반으로 감소하기 때문입니다. 거의 정렬되어 있을 때 가장 빠른 알고리즘입니다.

time : worst O(n^2), best O(n), average O(n^2)

Shell Sort(셸 정렬)

셸 정렬 은 비교정렬(bubble, selection, insertion, shell) 중에서 가장 성능이 뛰어난 알고리즘입니다. 그리고 이후에 나올 퀵 정렬 다음으로 수행속도가 빠르고 안정적입니다. gap = array.length / k로 정합니다. 저는 k 를 간단히 2로 정하였는데 k에 따라 성능이 좌우됩니다.

/**
* 셸 정렬에 의해 나누어진 부분 배열을 정렬할 삽입 정렬 알고리즘
* @param array 배열
* @param startIndex 시작 인덱스
* @param gap 증분
*/
void customInsertionSort(int[] arr, int startIndex, int gap) {
for(int i = startIndex + gap; i < arr.length; i+=gap) {
// 삽입정렬과 다르게 i가 startIndex + gap에서 시작하고 증분이 1이 아니고, gap이 된다.
int ai = arr[i];
int j;
for (j = i; j > startIndex && arr[j-1] > ai; j--) // j > 0 대신 j > startIndex 사용
arr[j] = arr[j - 1];
while (j > gap && arr[j-gap] > ai) { // arr[j-1] 대신에 arr[j-gap] 을 사용
arr[j] = arr[j-gap]; // arr[j-1] 대신에 arr[j-gap] 을 사용
j -= gap;
}
arr[j] = ai;
}
}
// 쉘 정렬
void shellSort(int[] arr){
for(int gap = arr.length/2; gap > 0; gap /= 2) { // main loop, gap 을 2씩 나눔.. 4, 2, 1
for (int startIndex = 0; startIndex < gap; startIndex++)
customInsertionSort(arr, startIndex, gap);
}
}
view rawshellSort.java hosted with ❤ by GitHub

셸 정렬은 기존 배열을 여러개의 sub sequence(부분 배열)로 분할하고 이에 대해서 삽입정렬 합니다. (병렬화) 이 sub sequence는 gap(증분) 을 이용해서 정의합니다. 저는 위의 코드에서는 gap 을 초기에 전체 길이의 1/2 로 잡았습니다. 전체 길이가 8인 다음 배열이 있습니다.

{a1,a2,a3,a4,a5,a6,a7,a8} // 초기 배열, 배열길이 8

위의 배열에서 처음 gap = 8/2 = 4 입니다.

{a1,a5} {a2,a6} {a3,a7} {a4,a8} // 원소를 4칸씩 건너뛰고 부분 배열을 생성. 각각 삽입정렬을 수행, 총 4회 삽입정렬
// iSort(a,0,4);
// iSort(a,1,4);
// iSort(a,2,4);
// iSort(a,3,4);

위의 4가지 sub sequence 로 나누어져서 main loop 1번째 회전이 끝날동안 이루어집니다.

이후 2회전에서는 gap = 4/2 = 2 입니다.

{a1,a3,a5,a7} {a2,a4,a6,a8} // // 원소를 2칸씩 건너뛰고 부분 배열을 생성총 2회 삽입정렬
// iSort(a,0,2);
// iSort(a,1,2);

위의 2가지 sub sequence 각각에 대하여 main loop 2번째 회전에 이루어집니다. 마지막에 전체를 대상으로 삽입정렬하여 마무리합니다. (gap = 2/2 = 1)

{a1,a2,a3,a4,a5,a6,a7,a8}
// iSort(a,0,1);

1회전 이후에 나오는 sub sequence(크기가 m) 들은 절반은 정렬된 상태이기 때문에 m/2 이상의 비교를 수행하지 않습니다.

gap 은 적당한 매개변수를 선택하여 그 값만큼 간격을 가진 데이터들을 하나의 시퀀스로 모아 삽입정렬을 실행합니다. (2가 아니어도 됩니다.) 이후에 적당히 줄여나가면서 정렬을 반복하고, 매개변수 값이 1이되면 종료합니다. 이 때, 매개변수는 근사적으로 소수여야합니다.

time : worst O(n^2), best O(n logn), average O(n^1.5) - gap 의 값에 따라서 성능이 좌우됩니다.

Merge Sort(합병정렬, 병합정렬)

분할-정복 프로세스를 사용한 알고리즘입니다. 합병 정렬은 분할하는 알고리즘과 합볍하는 알고리즘이 필요합니다. 이 2가지 배열을 합병하는 알고리즘은 3개의 큐를 생각는 것이 가장 좋습니다.

/**
* 비순환 드라이버 method
* @param arr
*/
void mergeSort(int[] arr) {
mergeSort(arr,0,arr.length);
}
/**
* 합병 정렬 - 분할하는 로직이 들어있고, 다른 합병정렬 알고리즘을 가지고 있는 함수를 실행합니다.
* @param arr 배열
* @param startIndex 시작 index
* @param last 처음에 배열의 길이를 입력 받고, -1 해서 마지막 인덱스로 사용됩니다.
*/
void mergeSort(int[] arr, int startIndex, int last) { // 오버로드로 선언 매개변수 개수만 다릅니다.
// 선조건 : 0 < startIndex < last <= arr.length
// 후조건 : arr[startIndex...last-1]은 오름차순이다.
if(last - startIndex < 2) return;
int middleIdex = (last + startIndex) / 2; // 배열의 중간 index
mergeSort(arr, startIndex, middleIdex); // [startIndex, middleIdex) 반열린구간
mergeSort(arr, middleIdex, last); // [middleIdex, last) 반열린구간
merge(arr, startIndex, middleIdex, last);
}
/**
* 합병하는 알고리즘입니다.
* @param arr
* @param startIndex
* @param middleIdex
* @param last
*/
void merge(int[] arr, int startIndex, int middleIdex, int last) {
// 선조건 : arr[startIndex...middleIdex-1] 과 arr[middleIdex...last-1] 은 오름차순이다.
// 후조건 : arr[startIndex...last-1] 은 오름차순이다.
if(arr[middleIdex -1] <= arr[middleIdex]) return;
int i = startIndex, j = middleIdex, k = 0; // k는 합병된 원소의 개수입니다.
int[] tempArr = new int[last - startIndex]; // 합병할때만 사용하는 임시 배열
while (i < middleIdex && j < last) // main loop
if(arr[i] < arr[j]) tempArr[k++] = arr[i++];
else tempArr[k++] = arr[j++];
if(i < middleIdex) System.arraycopy(arr, i, arr, startIndex + k, middleIdex - i);
// shift arr[i...midddleIndex - 1]
System.arraycopy(tempArr, 0, arr, startIndex, k); // copy tempArray[0...k-1] to arr[p...p+k-1]
}
view rawmergeSort.java hosted with ❤ by GitHub

위의 합병하는 로직이 있는 merge 함수에 main loop 가 종료되면 tempArr에는 두배열을 합친 정렬된 원소들이 들어있습니다. 그런데 2배열중에 좌측에 있는 배열에 합병되지 않은 원소가 생기는 경우가 있습니다.

if(i < middleIdex) System.arraycopy(arr, i, arr, startIndex + k, middleIdex - i); 

이때 위처럼 좌측 끝에 합병되지 않는 원소들을 끝으로 옮겨주는(shift) 작업이 필요합니다. k는 합병 정렬된 원소의 개수입니다. k 는 tempArr.length 와 같습니다.

일반적인 분할-정복프로세스에는 log n 단계의 분할과 log n 단계의 병합이 이루어집니다. 따라서 2log n 레벨을 가집니다. 각각의 레벨에서 n개의 원소가 비교되므로, 최대 비교 횟수는 2n * log n 번입니다. 실제로는 시간이 오래 걸리며, 외부정렬(대용량의 외부 기억장치를 사용하는 정렬 - 대용량 데이터를 정렬할 수 있습니다.)에 주로 활용합니다.

time : worst O(n logn), best O(n logn), average O(n logn)

Quick Sort(퀵 정렬)

pivot(피벗)을 활용하여 분할-정복 알고리즘을 사용하였습니다. 배열에서 pivot 을 정하고, 그것을 임시 보관한뒤 이를 중심으로 pivot 보다 작은그룹, 큰그룹 으로 나누고, 그 사이에 pivot 을 위치시킵니다.

/**
* 비순환 드라이버 method
* @param arr
*/
void quickSort(int[] arr) {
quickSort(arr,0,arr.length);
}
/**
* 퀵 정렬
* @param arr 배열
* @param startIndex 시작 index
* @param last 처음에 배열의 길이를 입력 받고, -1 해서 마지막 인덱스로 사용됩니다.
*/
void quickSort(int[] arr, int startIndex, int last) {
if(last - startIndex < 2) return;
int j = partition(arr, startIndex, last);
quickSort(arr, startIndex, j);
quickSort(arr, j + 1, last);
}
/**
* pivot 보다 큰 원소를 우측으로 작은 원소를 좌측으로 보내면서 마지막에 pivot 의 위치를 찾고 반환
* @param arr
* @param startIndex
* @param last
* @return pivot 의 index 를 반환합니다.
*/
int partition(int[] arr, int startIndex, int last) {
int pivot = arr[startIndex]; // 맨 앞에 있는 원소를 pivot정한 경우입니다.
int i = startIndex, j = last;
while (i < j) { // i == j 가 되면 loop 가 종료됩니다. 회전할때 마다 i가 증가되거나 j가 감소 됩니다.
while (j > i && arr[--j] >= pivot) ; //empty loop, j는 pivot 이 될때까지 1을 선감소
if(j > i) arr[i] = arr[j]; // arr[j]는 arr[i]로 복사되고, 빈공간이되었다고 봅니다.
while (i < j && arr[++i] <= pivot) ; //empty loop, i는 pivot 이 될때까지 1을 선 증가
if(i < j) arr[j] = arr[i]; // arr[i]는 arr[j]로 복사되고, 빈 공간이 되었다고 봅니다.
}
arr[j] = pivot; // i == j 인 상태입니다.
return j;
}
view rawquickSort.java hosted with ❤ by GitHub

평균적인 경우에 quick sort는 최선의 경우에 비교해 약 38% 정도만 더 비교를 수행합니다. 또한, 최선의 경우 퀵 정렬은 합병 정렬과 마찬가지로 반복적으로 시퀀스를 2개 부분배열과 한 개의 pivot으로 나눕니다.

퀵 정렬이 합병 정렬에 비교해 빠른 가장 큰 이유는 "제자리(in place)"에서 동작하는 것입니다. 모든 데이터 이동은 분할 프로세스에 의해 만들어지는 회전 때문에 수행되는데, 여기서는 하나의 임시 저장 위치(피벗을 위한)만을 사용합니다. 합병정렬은 임시저장소로 배열 전체를 사용하며, 배열에서 배열로 복사하는 데 시간이 걸리게 됩니다.

만약 배열이 이미 오름차순으로 정렬된 경우, 맨 앞에 있는 원소를 pivot으로 정할 경우 최악의 성능을 내게 됩니다. (pivot의 위치 어디에 선언하느냐에 따라 partition method의 source code도 달라집니다.) 이를 피하고자 java.util.Arrays.sort() 는 내부적으로 수정된 퀵 정렬을 사용하고 있습니다.

time : worst O(n^2), best O(n logn), average O(n logn)

Heap Sort(히프 정렬)

히프 정렬은 선형시간이 아니라 로그 시간에 각각의 선택을 수행할 수 있도록 선택 정렬을 개선한 것으로 볼 수 있습니다. 이것은 정렬되지 않은 부분 배열을 heap으로 유지하고, 최댓값이 a[0]에 위치하도록 합니다. 여기서 각각의 선택이란 a[0]를 내보내고 나서, 나머지 정렬되지 않은 부분 배열을 다시 히프화(heapify) 하는 것입니다. 이러한 연산은 단순히 히프화 연산을 사용하면 되므로, log n의 단계가 걸리게 됩니다.

/**
* heap 정렬을 합니다.
* @param arr
*/
void heapSort(int[] arr) {
for (int i = (arr.length - 1) / 2 ; i >= 0; i--)
heapify(arr, i, arr.length); // 모든 내부 node를 index가 큰 node 부터 root node(arr[0])까지 히프화합니다.
// arr[0](root node)에는 최댓값이 들어가고 모든 서브트리가 heap 이됩니다.
for (int j = arr.length - 1; j > 0; j--) {
swap(arr, 0, j); // 0번 원소와 j번 원소를 교환합니다.
heapify(arr, 0, j); // [0,j) 구간을 히프화 합니다.
}
}
/**
* 전달받은 node 번호와 자식 노드를 비교하여 히프화합니다.
* @param arr
* @param nodeIndex 히프화할 node 의 번호입니다.
* @param heapSize 완전 이진 트리의 크기입니다.
*/
void heapify(int[] arr, int nodeIndex, int heapSize) {
int ai = arr[nodeIndex];
while (nodeIndex < heapSize/2) { // arr[i] 는 leaf 가 아닌경우만 loop 를 순환합니다.
int j = 2 * nodeIndex + 1; // j는 ai의 좌측 자식 노드의 index 입니다.
if(j + 1 < heapSize && arr[j + 1] > arr[j]) ++j; // 우측 자식 노드의 값이 더 큰 경우 j를 후증가합니다.
if(arr[j] <= ai) break; // 부모가 자식노드보다 크면 loop 를 종료합니다.
arr[nodeIndex] = arr[j];
nodeIndex = j;
}
arr[nodeIndex] = ai;
}
view rawheapSort.java hosted with ❤ by GitHub

히프 정렬은 알고리즘 적으로 선택정렬과 삽입 정렬을 조합한 것으로 볼 수 있습니다. 히프정렬은 2단계로 구분할 수 있습니다. 첫 번째로 히프를 구축하고, 다음으로 제거하는 것을 통해 정렬합니다. 2단계 사이에서 히프는 부분 순서화 됩니다. 따라서 알고리즘은 삽입에 대해 부분정렬을 수행하고, 삭제에 대해 부분 정렬을 수행한다. 2개의 느린 알고리즘을 조합하여 빠른 알고리즘을 생성한 것입니다.

time : worst O(n logn), best O(n logn), average O(n logn)

Counting Sort(계수 정렬)

서로 다른 숫자 값이 키의 개수보다 훨씬 적은 경우 잘 동작하는 정렬 알고리즘입니다.

void countingSort(int[] arr) {
int n = arr.length;
int output[] = new int[n]; // 결과를 저장할 임시 배열
int count[] = new int[256]; // arr 에 정수 입력값중에 255 를 넘어가는 건 정렬되지 않습니다...
for (int i = 0; i < n; ++i)
++count[arr[i]]; // 계수 를 측정합니다.
for (int i = 1; i < 256; ++i) // 앞의 원소를 더하여 누적시킵니다.
count[i] += count[i - 1];
for (int i = n - 1; i >=0; i--) {
// 같은 키의 순서를 유지하기 위해 n-1에서 0으로 내려가면서 역순으로 실행하였습니다...
output[count[arr[i]] - 1] = arr[i]; // output 배열에 실제 정렬을 수행합니다.
--count[arr[i]]; // 정렬된 원소는 counting 계수를 1 감소시킵니다.
}
for (int i = 0; i < n; ++i)
arr[i] = output[i]; // 원본 배열에 결과를 저장
}
view rawcountingSort.java hosted with ❤ by GitHub

일반적으로 같은 키가 뒤섞이지 않도록 하는 정렬 알고리즘을 안정적(stable)이라고 합니다. 계수 정렬은 안정적인 정렬 알고리즘입니다. 계수 정렬의 중요한 응용중의 하나는 다차원 정렬(multidimensional sorting) 입니다. 기수 정렬이라고도 합니다.

Radix Sort(기수 정열)

계수 정렬의 다차원 응용에 해당하는 알고리즘입니다. 모든 key가 같은 d(문자열의 길이)를 가지는 string(문자열)이고, string에 있는 모든 문자는 정수집합{0,1... r-1}에 속해있다고 가정합니다. 예로 다음과 같은 것들이 있다.

  • SSN(미국사회보장번호, 055-23-2233) : d = 9, r=10
  • ISBN(도서 번호, 3-35463-943-X) : d = 1, r = 11

다음은 10자리 정수까지 정렬하는 기수정렬 예시입니다.

void radixSort(int[] arr) {
int[] result = arr ;
for (int place = 1; place <= 1000000000; place *= 10) {
result = countingSort(result, place);
}
for (int i = 0; i < arr.length; i++) {
arr[i] = result[i];
}
}
int[] countingSort(int[] input, int place) {
int[] out = new int[input.length];
int[] count = new int[10];
for (int i = 0; i < input.length; i++) {
int digit = getDigit(input[i], place);
count[digit] += 1;
}
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
for (int i = input.length - 1; i >= 0; i--) {
int digit = getDigit(input[i], place);
out[count[digit] - 1] = input[i];
count[digit]--;
}
return out;
}
int getDigit(int value, int digitPlace) {
return ((value / digitPlace) % 10);
}
view rawradixSort.java hosted with ❤ by GitHub

Buket Sort(버킷 정렬)

특정한 경우에만 효율적인 알고리즘입니다. 버킷 정렬의 실제 비용은 n개의 버킷을 할당하는 것입니다. 이러한 오버헤드는 이 알고리즘을 대부분의 경우 비실용적인 것으로 만듭니다.

void bucketSort(int[] a, int maxVal) {
int [] bucket=new int[maxVal+1];
for (int i=0; i<bucket.length; i++) {
bucket[i]=0;
}
for (int i=0; i<a.length; i++) {
bucket[a[i]]++;
}
int outPos=0;
for (int i=0; i<bucket.length; i++) {
for (int j=0; j<bucket[i]; j++) {
a[outPos++]=i;
}
}
}
view rawbucketSort.java hosted with ❤ by GitHub

java.util.Arrays.sort() method

자바 유틸 클래스 중에 Arrays에 포함된 sort 함수 내부는 퀵 정렬과 합병 정렬을 이용해서 구현되었습니다. boolean을 제외한 각각의 primitive type(기본형) 배열을 위한 sort() 함수와 Object type 배열을 위한 sort() 함수를 가지고 있습니다. 기본형을 위한 sort() 함수는 개선된 quick sort 알고리즘을 사용하고, Object를 위한 sort() 함수는 개선된 합병 정렬을 사용합니다. quick sort는 순환호출이 작은 부분배열로 내려가게 되면 약간 비효율적이게 되는데, 길이가 일정한 경곗값보다 작아지게 될 때 부분배열을 정렬하는 순환 호출이 비순환 알고리즘으로 전환된다면 알고리즘은 더 빨리 지게 됩니다. 이를 위해 sort() 함수는 내부적으로 경곗값을 7로 설정하였고, 부분배열의 길이가 7보다 작아지게 되면 삽입정렬을 호출하게 되어있습니다. 여기에 더해서 pivot을 선택할때, 첫 번째, 마지막, 가운데 원소 중에서 중간값을 선택하도록 하였습니다. 이렇게 하여, 이미 정렬되어있는 배열에 대해서 최악의 경우 O(n^2)가 발생하는 것을 방지해줍니다.

Object를 위한 개선된 합병정렬은 기본형과 마찬가지로 배열의 길이가 경곗값 7 보다 작아지면 삽입정렬로 전환됩니다. 또한, 여기에 불필요한 합병을 피하는 방법을 구현하였습니다. 합병에 대한 호출은 첫 번째 배열의 마지막 원소가 두 번째 배열의 첫 번째 원소보다 큰지를 검사합니다. 만일 크지 않다면 선형 시간을 가지는 합병 정렬대신 간단한 상수 시간을 가지는 연결(concatenation)을 수행합니다.



블로그 이미지

낭만가을

,

자신이 여러 개의 알고리즘 온라인 저지(Online Judge) 사이트에서 문제를 풀고 있다면, 전체 소스코드를 편하게 관리하기 위하여 깃 허브(Git Hub)를 이용할 필요가 있습니다. 또한 특정한 문제를 만났을 때 자신이 이전에 해당 문제를 푼 경험이 있다면 깃 허브를 통해 바로 해당 문제의 소스코드를 확인할 수 있기 때문에 깃 허브를 이용하면 친구와 함께 알고리즘 공부를 할 때에도 큰 도움이 될 겁니다.

※ 깃 허브 가입하기 ※

  ▶ 깃 허브: https://github.com/

  깃 허브 공식 사이트는 위와 같습니다. 접속하신 뒤에 회원가입 및 로그인을 진행해주세요. 그러면 새로운 소스코드 저장소(Repository)를 생성할 수 있습니다. 아래 그림과 같이 말입니다.

  이후에 다음과 같이 하나의 리포지터리를 만들어주시면 됩니다. 저는 코드 업(Code Up) 사이트에서 푸는 문제의 소스코드를 저장하기 위해 'Code Up Algorithm'이라는 이름을 붙여 보았습니다.

  생성 이후에는 다음과 같이 깃 주소가 나오게 됩니다.

※ 깃 데스크탑으로 클론(Clone)하기 ※

  이후에 위와 같이 만든 깃 허브 리포지터리에 소스코드를 업로드하기 위해서는 깃 데스크탑과 같은 깃 허브 응용 프로그램이 설치가 되어 있어야 합니다.

  ▶ 깃 데스크탑 주소: https://desktop.github.com/

  위 깃 데스크탑 공식 사이트에 접속하고, 깃 데스크탑 소프트웨어를 설치한 이후에 아까 전에 깃 허브에 가입한 계정으로 로그인까지 진행하시면 됩니다.

  그리고 File → 'Clone repository'를 하여 클론(Clone)을 수행합니다.

  아까 전에 자신이 만든 깃 허브 리포지터리 주소를 그대로 붙여넣기하여 만들어줍니다. 그리고 해당 깃이 저장될 파일 경로를 지정해 클론(Clone)을 수행하시면 됩니다.

  이제 위와 같이 해당 파일 경로에 깃이 생성된 것을 알 수 있습니다.

※ 소스코드 작성 및 푸시(Push)하기 ※

 이제 한 번 다음과 같이 하나의 텍스트 파일을 생성해 소스코드를 작성해봅시다.

  그러면 아래와 같이 깃 데스크탑에서도 실시간으로 소스코드가 반영되는 걸 확인할 수 있습니다.

  깃 허브에 업로드하기 위해서는 먼저 아래와 같이 변경된 소스코드에 대한 설명을 기입합니다. 저는 제목으로 'Correct: 1001'을 입력했습니다. 그리고 'Commit to master'를 눌러 커밋을 진행하시면 됩니다. 이 때 커밋(Commit)은 자신 컴퓨터의 깃에 적용되는 것입니다.

  커밋 이후에 실제 깃 허브에 적용되도록 하려면 푸시(Push)를 해주시면 됩니다. 다음 그림과 같이 'Publish branch'를 누르시면 푸시가 진행됩니다.

  깃 허브에 업로드가 이루어지면 다음과 같이 깃 허브 사이트에 접속했을 때 업데이트가 되어있는 것을 확인하실 수 있습니다.



블로그 이미지

낭만가을

,

인공지능을 연구하는 사람들의 궁극적인 목표는 우리가 고민해야 하는 골치 아픈 문제들을 인공지능이 대신 생각하게 해주는 것이다. 그렇다면 생각한다는 것에 대한 연구가 먼저 이루어져야 하고 연구자들은 인간의 뇌를 공부하기 시작했다.

인간의 뇌는 아직까지도 완벽하게 연구되지 못 할 정도로 복잡하지만 뇌를 구성하는 기본 단위인 뉴런의 동작 원리는 놀랍게도 단순했다.

Neuron (출처 : http://sebastianraschka.com)

인간의 뇌는 기본 단위인 뉴런(Neuron)이 무수히 연결되어 있는 모습을 하고 있다. 뉴런 하나의 모습을 살펴보면 Dendrites라고 하는 부분에서 외부 신호를 수용하고 Axon을 통해 신호를 출력한다. 이런 뉴런이 무수히 많이 연결되어 있는 형태가 인간의 뇌다.

이런 뉴런을 수학적 모델로 다시 그리면 다음과 같다.

딥러닝(Deep Learning)의 기본을 이루는 뉴런

뉴런에 있는 각 Dentrites들은 시냅스(Synapse)라고 하는 접점을 통해 외부 뉴런과 연결된다. 뉴런은 입력으로 들어오는 여러 개의 신호들을 하나로 합산한 다음 Activation Function을 통해 자신의 출력으로 만들어 낸다. 만들어낸 출력은 다시 다른 뉴런의 입력으로 들어가게 된다.

이전에 다뤘던 Logistic Regression을 한 번 다시 보자.

입력값의 행렬인 X와 가중치의 행렬인 W를 곱한 값이 있고,

그 값을 시그모이드 함수에 통과시켰다.

이를 뉴런 모델에 적용하면 다음과 같이 그릴 수 있다.

딥러닝(Deep Learning)의 기본을 이루는 뉴런

뉴런으로 들어오는 입력들을 X라고 하는 행렬에 표현하고 각 입력에 해당하는 가중치를 W 행렬에 표현한다. 두 행렬을 곱한 값이 Cell body에서 수행하는 작업이며, 이 값에 시그모이드 함수를 적용한 값이 이 뉴런의 최종 출력값이 된다.

Multinomial Classification은 Logistic Regression 모델을 N 개 적용한 것과 같으므로 위 그림처럼 그릴 수 있게 된다. 이런 뉴런이 서로 복잡하게 얽혀있는 모습은 다음과 같이 그려볼 수 있다.

딥러닝(Deep Learning)의 기초인 뉴럴 네트워크(Neural Network)

각 뉴런들이 복잡하게 연결되어 있고 각 연결마다 가중치가 존재하게 된다. 이런 뉴런들의 복잡한 연결을 뉴럴 네트워크(Neural Network)라고 하며 딥러닝의 원래 이름이라고 할 수 있다.

머신 러닝 모델과 XOR 문제

머신 러닝 초기 연구진들은 인공지능에 대해 생각하면서 X1과 X2를 입력받아 Y를 출력하는 일종의 논리 게이트를 만들어 복잡하게 연결하면 인간처럼 논리적 사고를 할 수 있을 거라고 생각했다.

두 개의 입력 값을 받아서 새로운 결론을 도출해내는 모델을 생각해냈다. AND 연산과 OR 연산은 Linear 한 모델 하나로 분리가 가능했다.

(출처 : 모두를 위한 딥러닝 강좌 시즌1)

두 개의 입력 X1과 X2가 0, 1의 값을 가질 수 있을 때, OR 연산과 AND 연산은 하나의 직선으로 표현이 가능했다.

(출처 : 모두를 위한 딥러닝 강좌 시즌1)

문제는 XOR였다. 머신 러닝을 연구하는 연구진들은 이 XOR 문제를 간단한 모델로 풀 수 있는지를 고민했다. 그러다가 MIT AI Lab의 Marvin Minsky라고 하는 교수가 하나의 모델을 이용하여 XOR 문제를 풀 수 없다는 것을 수학적으로 증명해 버렸다. 간단한 모델로 풀 수 없음이 증명된 것이다.

Multi Layer Perceptron

이어 하나의 모델이 아닌 하나 이상의 레이어(Layer)를 갖는 MLP(Multi Layer Perceptrons, Multi Layer Neural Nets)를 이용하여 XOR 문제를 해결할 수 있음을 제시했다. 저런 모델을 여러 개 이어 붙여서 XOR을 구현할 수 있음을 제시한 것이다.

하지만 더 큰 문제는 이 여러 레이어(Layer)를 갖는 Multi Layer Perceptron을 학습시킬 방법이 없었다는 것이다. 여러 레이어에 걸쳐 연결된 Perceptron 사이의 가중치를 데이터를 통해 학습 시킬 방법이 당시에는 알려져 있지 않았다. Marvin Minsky 교수는 실망한 나머지 자신의 책을 통해 Multi Layer Perceptron을 학습 시킬 방법은 존재하지 않는다고 발표해버린다. 이 책을 읽고 많은 연구진은 Neural Network에 대한 관심을 잃게 된다.

Backpropagation

그러다가 1974년, 1982년 Paul Werbos라는 연구자와 1986년 Hinton이라는 사람에 의해 Backpropagation이라는 알고리즘이 고안되었다. 

기존 Neural Network의 큰 문제는 Input에서 Output 쪽으로 값이 전파되기 때문에 최종적으로 Output 값이 실제와 달랐을 때 앞쪽에 있었던 Layer의 가중치를 조절하기가 힘들다는데에 있었다.

Backpropagation 알고리즘의 원리는 간단하다. Forward propagation으로 예측한 결과 값이 틀린 경우, 그 에러를 다시 반대 방향으로 전파시켜가면서 가중치 W 값을 보정해나가는 개념이다.

이러한 개념을 1974년 Paul Werbos가 자신의 박사 논문에 추가했다. 이후 1982년도 다시 논문을 발표했지만 이미 식어버린 관심을 살릴 수는 없었다. 이후 Paul Werbos와는 독립적으로 Hinton이라는 사람이 1986년에 같은 개념을 소개하는 논문을 발표하게 되었고, 조금씩 사람들의 관심을 받기 시작했다.

또 LeCun이라는 교수에 의해 수행된 고양이 실험에서 특정 모양에 대해서 특정 뉴런만 반응한다는 것을 알게 되었다. 일부 신경들의 그림의 부분부분들을 담당하고 그것들이 나중에 조합되는 것이 아닐까 하는 생각을 이용해서 'Convolutional Neural Networks'라고 하는 알고리즘을 개발해냈다. 우리가 잘 알고 있는 알파고 역시 CNN 알고리즘을 사용했었다. 
 이미지의 일부분을 잘라서 입력으로 주고 나중에 다시 합치는 방법인 CNN은 글자 인식 등의 부분에서 높은 성능을 발휘했다. 인식률이 90%에 달할 정도로 높은 성능을 보여줬다. 이후 CNN 알고리즘은 자동주행 차량 연구에도 사용되었다.

학습 성능 문제

하지만 새로운 문제에 봉착했다. Backpropagation 알고리즘을 학습할 때, Neural Network의 Layer 수가 많아질수록 성능이 나빠졌다. output 쪽의 에러를 input 쪽으로 전파해야 하는데, Layer가 많아질수록 input 쪽에 있는 앞단에 에러가 전파되지 않는 문제가 생겼다.

수많은 레이어들 (출처 : http://neuralnetworksanddeeplearning.com/chapp6.html)

실제로는 모든 노드의 가중치를 적절하게 조정해야 하지만 Backpropagation으로 전파되는 에러의 흔적이 Layer를 거듭할수록 옅어져 input Layer 쪽에서는 거의 변동이 없게 되는 것이다. 실제로는 입력 쪽 Layer의 가중치가 더 중요한데 에러가 잘 전파되지 않아 성능 향상이 어려워진 것이다.

Neural Network가 이렇게 어려움을 겪고 있는 사이 다른 머신 러닝 알고리즘이 두각을 나타내기 시작했다. SVM, RandomForest 등의 알고리즘이 소개되었다. 이런 알고리즘은 Neural Network보다 간단하고 이해하기 쉬우면서 성능도 준수해서 더욱더 주목을 받을 수 있었다.

이에 1995년 CNN을 고안한 LeCun 교수조차도 SVM이나 RandomForest 같은 알고리즘이 더 간단하고 더 성능이 좋게 나온다고 말을 했다. 여기서 딥러닝의 2차 침체기가 도래했다.


'프로그래밍 > 알고리즘' 카테고리의 다른 글

정렬 알고리즘  (0) 2018.06.22
GIT 에 소스 커밋하기  (0) 2018.06.22
시간 복잡도  (0) 2018.04.21
[Codility] CountSemiprimes  (0) 2018.04.21
[Codility] cyclicRotation  (0) 2018.04.15
블로그 이미지

낭만가을

,

한화생명 리치100세연금보험

 

이보험은 공시이율형 연금보험으로써 특징적인 것은 없고 현 공시이율이 어느정도 인지를확

 

인해보시면 됩니다.

 

 

 

위표에서 보면 연금보험 설계서는 45세 남성, 연금수령방법은 개인형 100세보증,월납 50만원

 

연금개시 65세로 설정하였고,노후에 연금액이 얼마나 될지 한번 보겠습니다.

 

 

위표는 리치100세 연금보험의 연금수령형태입니다. 연금수령형태는 굉장히 다양한 편으로 장점이

 

될수 있습니다. 종신연금형,확정연금형,상속연금형 등으로 구분됩니다.

 

 

연금보험은 저축성이기는 하지만 10년이후에 비과세 혜택을 부여받기 위해서 사망시 사망보험

 

금을 지그배주고 있습니다. 피보험자 사망시 사망보험금 600만원이 지급되고 사망당시의 계

 

약자적립금을 지급합니다.

 

 

이 연금보험 납입시 고액보험료를 납입하게 되면 보험료 할인 혜택을 받게됩니다.30만원 이상

 

인 보험료에 대해서 할인을 적용해주고 있으며 30만원 초과된 금액에  대해서는 0.5% 이사의

 

보험료를 할인해주고 한 회사에 5인이상이 한화생명의 보험을 가입하면 단체취급으로 보험료

 

1%를 할인해줍니다.

 







 

연금보혐을 10년 납입하고 10년 거치 후 연금개시하도록 설계 하였습니다.

 

총 5,999만원을 납입하고 20년 되는 시점에 현 공시이율 4.4%적용시 1억 151만원 정도의

 

해지환급금이 발생합니다.최저보증이율로 계산하게 되면 7,283만원을 해지환급금으로 적용

 

받게 됩니다. 20년동안 이율이라고 봤을때 너무 터무니없는 금액이 아닐수있을겁니다.

 

 

 

한화생명리치100세보험 사업비입니다. 사업비를 10년동안 많이 받는데 이유는 나중에 평생

 

토록연금을 지급해주기 때문이며,7년 미만 11.65%.7년 이상10년 미만 9.52%, 10년 이후 2,000

 

원을 사업비로  받습니다.

 

 

추가납입은 납입액의 2배까지 가능합니다. 추가납입은 사업비를 줄이는 좋은 방법입니다.

 



출처: http://viewhelp.tistory.com/entry/한화생명리치100세연금보험 [보험트렌드]

블로그 이미지

낭만가을

,