반응형
git

Git simple guide


crazyj7@gmail.com

Start git repository download

git clone http://github.com/crazyj7/...git
git clone ssh://git@192.168…:2222/home/git/repos/…git

Work

make new branch and work

최신 master 브랜치를 받아서 작업 브랜치를 만들고 작업한다.

git pull
git branch alpha
[work to do…]

commit and push

변경된 파일들을 index표시를 하고 커밋한다. 그 후 원격 서버에 올린다.

git status .
git add -u
git add [files/dirs]
git commit -m “update message”
git push (or git push origin master)

merge to master

마스터 브랜치를 기준으로 새 작업 브랜치를 가져와 병합 한다.
병합후 변경내역을 원격 서버에 올린다.

git branch : 현재 브랜치 확인
git checkout master
현재 브랜치가 master로 변경됨
git merge alpha
현재 브랜치 기준으로 alpha 브랜치를 가져와 병합한다.
git push

rollback

작업한 파일을 원래대로 되돌리기(Warn!)

git checkout [file] or [. (current dir)]

마지막 커밋은 취소하고 수정했던 것도 전부 취소하기(Warn!)

cancel last commit
git reset --hard HEAD^ (HEAD~1 in Windows)
위 옵션에서 --hard 옵션을 빼면 커밋만 취소하고 수정 파일은 그대로 유지한다. (주의!!! 수정내역이 없어지므로 필요시 백업!)
git reset HEAD^

Cancel Merge (병합 취소)
merge후 conflict나고 처리가 복잡할 경우 바로 이전으로 돌아가기

git merge --abort


History

GUI로 히스토리를 확인할 수 있다.

gitk

한글이 깨질 경우 hangul encoding 변경 후, 다시 시작

git config --global gui.encoding utf-8


Errors

pull fail?

cancel all worked here. cancel commit.
변경 내역을 되돌리고, 다시 pull로 원격에서 업데이트한다.(Warn! 주의!!! 작업내용삭제됨!!! 일단 백업해 두는 것을 추천.)

git reset --hard HEAD^ (HEAD~1 in Windows) or HEAD
git pull

그래도 pull이 실패한다면 stash로 작업내역을 백업하고 다시 받는다.

git stash
git pull

참고

git reset --soft HEAD~ 는 HEAD를 한 커밋 이전으로 이동시킨다.
git reset HEAD~ 는 HEAD 이동 및 index도 이동한다.
git reset --hard HEAD~ 는 HEAD 이동, index 이동, working dir도 이전으로 돌린다.
git stash 는 reset을 하지만 변경내역은 백업을 해 둔다. 파일명 지정시 git stash save [file] , git stash list , git stash pop/apply 로 불러오기. 다른 브랜치에 잘못 작업한 것을 원래 브랜치로 이동시킬 때 사용가능

cancel git add?

git reset [file/dir]

conflict?

edit conflicted file and git add/ git commit
or choose one side

작업하고 commit을 하고 원격으로 push하는데 conflict가 발생할 수 있다. 이것은 원격에 이미 checkout받은 브랜치가 변경되었다는 것이다.

git push : 리모트에서 거부 발생!!!
git pull
conflict!!! 자동병합 충돌 발생!!! 충돌 파일 확인!!
git status : 충돌파일 정보
파일이 병합처리되어 >>>(원격) <<<(로컬) 등 문자 포함
이 때는 파일을 수정하고 다시 커밋하고 푸시하는 방식이 있고, 어느 한 쪽을 선택할 수도 있다.

충돌 발생시 충돌 파일을 수정하든지 어느 한 쪽을 골라야 한다.
현재 브랜치 기준으로 내것과 원격의 것을 잘 구분해야 한다.

git checkout --ours [file] : 로컬파일이 진짜다. 로컬 우선!!!
git checkout --theirs [file] : 서버에 있는 최신것을 따르겠다. (주의!!! 로컬 파일 내용은 없어짐!!! 로컬을 무시하겠다.)

or edit file (양쪽을 모두 반영하겠다. >>> <<< 파일 수정 )
git add -u
git commit -m “update”
git push

cancel delete local file

파일을 잘못 삭제했을 경우 복구하는 법

git status . ; check which file is deleted.
git checkout HEAD [file]

cancel work

git reset . ; reset all worked
git checkout . ; go before work


Ignore files

If you dont want to upload some files or dirs,
create .gitignore file in the current directory.
add files or dirs
ex)

build/
*.obj
dataset/
*.o


Branch merge

  • fast-forward
    only one branch is changed or it doesn’t exist same file changed.)
    a -> b(master) : no change
    b(newbranch) -> x ->y(bugfix)
    merge : a->b->x->y (master=bugfix)
    git push or git pull
    특별히 겹치는 부분이 없으면 자동으로 충돌없이 병합된다.
  • merge commit
    Both branches are changed. Update conflict files and commit
    git checkout master : 마스터를 가져와서 (항상 메인을 기준으로)
    git merge alpha : 알파를 불러와 현재(마스터)와 합친다.
    충돌이 나면 해당 파일을 수정하고 병합한다. 여러 브랜치가 하나의 브랜치(현재 브랜치)로 합쳐진다. 과거 히스토리 유지.
  • rebase
    a -> b -> c -> d (master)
    b -> x -> y (alpha(bugfix))
    위 버그 수정 브랜치를 마스터로 반영하고, 마스터만 유지하고 싶다. 그런데 버그패치동안에 마스터가 변경된 상태다.
    merge: a->b->c->d ->x->y (master=bugfix)
    git checkout alpha : 수정 브랜치를 가져와서
    git rebase master : 마스터에 연결시도
    update conflict files : 충돌발생 파일 수정(c,d,x,y)
    git add -u
    git rebase --continue : 리베이스 계속 진행
    git checkout master : 마스터를 가져와서
    git merge alpha : 알파를 현재로 불러와서 병합.
    베이스를 새로 지정한다. 위의 브랜치 트리가 한 줄로 만들어진다. 과거 히스토리 변경 주의.

Delete branch

브랜치 삭제 -d 옵션으로 안되면 -D 옵션으로 한다.

git branch -d [alpha]


Delete file

로컬 및 저장소에서 파일 삭제

  • Remove the file in both local and remote github
    git rm [file]

저장소에서만 삭제하고 로컬 파일은 보존

  • Remove remote file in github but remain it in local
    git rm --cache [file]

Delete all .git files

리눅스에서 모든 .git 폴더 제거하기(incude subdir)

check files…
find . -name ‘.git’
WATCHOUT!!!
find . -name ‘.git’ -prune -exec rm -rf {} +

윈도우에서 모든 .git 폴더 제거하기(incude subdir)

batch file create
FOR /r “c:\temp” %%f IN (.git) DO RD /s /q “%%f”

삭제하기 전에 목록 출력만(rd /s /q 대신 echo) 해서 확인을 하는 것이 좋다.

Repository mirror

저장소 복사

git clone --mirror [가져올 URL]
git push --mirror [가져욜 URL]

# git remote -v 
원격지 저장소 주소 확인

# git clone --mirror https://user@a.c.com/maypp/test.git
먼저 옮길 내용을 클론으로 받는다.

올릴 곳의 주소로 설정
# git remote set-url --push origin http://local.com/mobile/android.git
# git push --mirror
이제 로컬의 내용을 변경된 주소로 올린다.

Tag

태그는 버전명을 주거나 할 때 지정해 준다.

  • 먼저 checkout으로 받고, 그 안으로 들어가서 작업한다.
  • 현재 갖고 있는 태그 목록
git tag
  • 현재 받은 checkout에 tag를 만들어 걸기
git tag v1.0
git push origin v1.0
-- 이렇게 해서 서버로 올린다.
  • 태그로 받기
git checkout v1.0
  • 태그 삭제
git tag -d v1.0

-태그 v.1.0을 수정할 때는 1.1 브랜치를 만들어서 작업

태그로 가져와서
git checkout v1.0
브랜치를 만들고
git branch 1.1
해당 브랜치로 전환(이걸 안해주면 소스 날릴 수도)
git checkout 1.1
수정작업
git add -u
git commit -m "patch 1.1"
git push

-master로 위 브랜치 합치기

마스터로 가서
git checkout master
브랜치 1.1을 가져와 머지함
git merge 1.1
git status
충돌파일 편집 수정
git add -u
git commit -m "merge 1.1"
git push
태그를 추가
git tag v4.0
git push origin v4.0

Author : crazyj7@gmail.com

'Develop > Linux_Unix' 카테고리의 다른 글

[도커] tomcat, mariadb 환경 war hang/slow  (0) 2021.04.28
Bash Tip 작업속도를 빠르게  (0) 2021.03.03
리눅스 백그라운드 실행(터미널종료에도)  (1) 2021.02.23
Ubuntu18/tomcat8 setup  (0) 2019.11.08
VI 사용법  (0) 2015.06.02
반응형
sort compare

Sort Algorithm Compare

  • 시험 방법
    정렬 알고리즘들을 500~550개(랜덤)의 값을 만들어 정렬하는 것을 5000번 반복한 시간을 측정하였다.
qsort test
ALG=selection_sort
OK cnt=5000 FAIL cnt=0
4029 ms
ALG=bubble_sort
OK cnt=5000 FAIL cnt=0
3190 ms
ALG=insertion_sort
OK cnt=5000 FAIL cnt=0
2257 ms
ALG=merge_sort
OK cnt=5000 FAIL cnt=0
361 ms
ALG=quick_sort
OK cnt=5000 FAIL cnt=0
236 ms
  • 랜덤한 값들을 정렬할 경우 알고리즘별로 시간 측정 결과 대략적으로 다음과 같은 순서로 성능이 좋았다. 퀵소트 이름이 괜히 퀵이 아니다.
  • quick > merge > insertion > bubble > selection
  • 위 결과는 정렬할 대상의 상태(값 배열)에 따라 달라질 수 있다.
#include <iostream>
#include <vector>
#include <ctime>
#include <chrono>

void selection_sort(int arr[], int size) {
    for(int i = 0 ; i < size - 1 ; i++) 
        for (int j = i + 1 ; j < size ; j++) 
            if(arr[i] > arr[j]) {
                // swap(arr[i], arr[j]);
                int t = arr[i] ;
                arr[i] = arr[j] ;
                arr[j] = t ;
            }
}


void bubble_sort(int a[], int n){
    int i, j, t;
    for (i = 0; i < n - 1; i++) {
        int bchanged=0 ;
        for (j = 1; j < n - i; j++) // j=(1,10)
        {
            if (a[j - 1] > a[j]){
                t = a[j - 1];
                a[j - 1] = a[j];
                a[j] = t;
                bchanged=1 ;
            }
        }
        if (bchanged==0) break ;
    }
}


void insertion_sort(int arr[], int size) {
    for(int i = 1 ; i <= size - 1 ; i++) 
        for (int j = i-1 ; j >= 0 ; j--) 
            if(arr[j] > arr[j+1]) {
                // swap(arr[j], arr[j+1]);
                int t = arr[j] ;
                arr[j] = arr[j+1] ;
                arr[j+1] = t ;
            } 
            else
                continue;
} 



void merge_sort(int arr[], int size) {
    // std::cout << "merge_sort size=" << size << std::endl ;

    if (size > 2) {
        // 왼쪽 반, 오른쪽 반을 나누어 반복.
        merge_sort(arr, size / 2);
        merge_sort(arr + size / 2, size - size / 2);
        
        // 왼쪽, 오른쪽 반이 각각 정렬된 상태임. merge한다.
        int leftCursor = 0;
        int rightCursor = size / 2;
        //int buff[50];
        int *buff = new int[size] ;

        int buffCursor = 0;
        // 두 그룹을 각각 스캐닝하면서 순서대로 기록. (어느 한쪽이 끝날때까지)
        while (leftCursor < size / 2 && rightCursor < size) {
            if (arr[leftCursor] < arr[rightCursor]) {
                buff[buffCursor++] = arr[leftCursor++];
            } else {
                buff[buffCursor++] = arr[rightCursor++];
            }
        }
        // 남은 한 그룹의 데이터를 append 
        for (int i = leftCursor ; i < size / 2 ; i++)
            buff[buffCursor++] = arr[i];
        for (int j = rightCursor ; j < size ; j++) 
            buff[buffCursor++] = arr[j];
        memcpy(arr, buff, size * sizeof(int));
        delete[] buff ;
    } else { // 원소 개수가 2개 이하인 경우, 비교하여 정렬한다.
        if (arr[0] > arr[1]) {
            // swap(arr[0], arr[1]);
            int tmp = arr[0] ;
            arr[0] = arr[1] ;
            arr[1] = tmp ;
        }
    }
}



// a: 정렬할 데이터 array
// n: 데이터 개수
void quick_sort(int a[], int n){
	int v, t;
	int i, j;
	if (n > 1){
		v = a[n - 1]; // v=축값. 마지막 노드값을 사용
		i = -1; 
		j = n - 1; 
		while (1){ // 분할
			// while (a[++i] < v); // 왼쪽에서부터 축값보다 크거나 같은 값이 있는지? -> 없다면??? 없을수는 없다. 자신끼리 비교가 마지막.
            while (a[++i]<v) {
                // std::cout << "debug : i=" << i << std::endl ; 
            }

			// while (a[--j] > v); // 오른쪽에서부터 축값보다 작거나 같은 값이 있는지? -> 가장작은값이 pivot이면?? index out range???
            while( a[--j]>v) {
                // std::cout << "debug : j=" << j << std::endl ; 
                // minus index로 갔는데 에러가 발생하지 않았지만, 쓸데없는 오버로드다. 다른 언어였으면 indexerror이다. 
                if (j==0)   // 전체 검색 완료이므로 더 이상 할 필요없다.
                    break ;
            }
			if (i >= j) 
                break; // i와 j의 위치가 뒤바뀌었으면 분할 끝. 좌우 분할이 이미 잘되어 있다. 
            // i와 j의 위치가 좌, 우 상태 그대로 라면 
			t = a[i]; // 두 값을 바꿈. 
			a[i] = a[j];
			a[j] = t;
		}
        // 피봇이 들어갈 자리는? 왼쪽을 기준으로 정렬이 다 된 상태에서 마지막 i자리에 큰 값이 와 있다. 
		t = a[i]; // 축 값과 축값의 위치에 있는 값을 바꿈
		a[i] = a[n - 1];
		a[n - 1] = t;
        // i위치 기준으로 좌우 대소 분할 완료.
		quick_sort(a, i); // 왼쪽 구간 퀵정렬. (i개만 한다. 즉, i위치는 개수에 포함 안함.)
		quick_sort(a + i + 1, n - i - 1); // 오른쪽 구간 퀵정렬 (index로 치면 a+i+1부터 a+n-1. 따라서 개수는 a+n-1 - (a+i+1)+1 )
	}
}



void print_array(int *a, int n) {
    for(int i=0; i<n; i++)
    {
        std::cout << a[i] << " " ;
    }
    std::cout << std::endl ;
}

int check_asc(int *a, int n) {
    if (n<=1) return 1 ;
    for (int i=1; i<n; i++) {
        if (a[i-1]>a[i])
            return 0 ;
    }
    return 1 ;
}

int test_alg(void (*pfunc)(int[], int)) {
    int cnt = std::rand()%50+500 ;
    int *a = new int[cnt] ;
    int bcheck=0 ;

    if (true) {
        // 랜덤값 생성
        for (int i=0; i<cnt; i++) {
            a[i]=  std::rand()%1000 ;
        }
    } else {
        // 이미 정렬된 상태값 생성
        for (int i=0; i<cnt; i++) {
            a[i]=  i ;
        }
    }

    // print_array(a,cnt) ; // 정렬 전.
    // (*pfunc)(a, cnt) ;   // 이렇게 해도 가능.
    pfunc(a,cnt) ;
    // print_array(a,cnt) ; // 정렬 후.
    bcheck = check_asc(a,cnt) ;

    delete[] a ;
    return bcheck ;
}


uint64_t getmilli() {
    using namespace std::chrono;
    return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() ;
}


int main() {

    std::cout << "sort test" << std::endl ;
    std::srand(std::time(NULL)) ;

    // int a[] = {3,8,5,1,9,4,2,6,7, 10} ;
    // int a[10] ;
    // for (int i=0; i<10; i++) {
    //     a[i] = std::rand()%50 ;
    // }
    // int n = sizeof(a)/sizeof(int) ;
    // print_array(a, n) ;
    // quick_sort(a, n) ;
    // merge_sort(a, n) ;
    // bubble_sort(a, n) ;
    // print_array(a, n) ;
    // return 0 ;

    int bcheck=0 ;
    int okcnt = 0, failcnt=0 ;
    uint64_t ts, te ;


    const char *pfunc_name[] = { "selection_sort",  "bubble_sort", "insertion_sort", "merge_sort",  "quick_sort",   NULL} ;
    void(*pfunc[])(int[], int) = { selection_sort, bubble_sort, insertion_sort, merge_sort, quick_sort,  NULL };
    int pfunc_cnt = sizeof(pfunc) / sizeof(pfunc[0]) ;

    for (int kk=0; kk<pfunc_cnt; kk++) {
        okcnt=0 ;
        failcnt=0 ;
        if (pfunc[kk]==NULL)
            break ;
        std::cout << "ALG=" << pfunc_name[kk] << std::endl ;

        ts = getmilli() ;
        for (int i=0; i<5000; i++) {
            bcheck = test_alg(pfunc[kk]) ;
            if (bcheck) {
                okcnt++ ;
                // std::cout << "OK" << std::endl ;
            } else {
                failcnt++ ;
                // std::cout << "FAIL" << std::endl ;
            }
        }
        te = getmilli() ;
        std::cout << "OK cnt=" << okcnt << "  FAIL cnt=" << failcnt << std::endl ;
        std::cout << te-ts << " ms" << std::endl ;
    }

    return 0 ;
}

만약 이미 정렬된 상태를 다시 정렬을 시키면?

qsort test
ALG=selection_sort
OK cnt=5000 FAIL cnt=0
1507 ms
ALG=bubble_sort
OK cnt=5000 FAIL cnt=0
16 ms
ALG=insertion_sort
OK cnt=5000 FAIL cnt=0
1439 ms
ALG=merge_sort
OK cnt=5000 FAIL cnt=0
164 ms
ALG=quick_sort
OK cnt=5000 FAIL cnt=0
1329 ms
  • 위 경우, bubble, merge가 성능이 좋았다. bubble이 좋았던 이유는 바로 이미 정렬되어 있는지를 처음 루프에서 알아낼 수 있기 때문에 그 조건으로 루프 탈출이 가능하기 때문이다.
  • 위 조건은 quick 소트 입장에서는 worst case이다. 먼저 이미 정렬되었는지 검사하는 루틴을 추가한다면 이런 경우를 방지할 수 있을 것이다.

Author: crazyj7@gmail.com

'Develop > C&CPP' 카테고리의 다른 글

[알고리즘] 정렬5: quick sort  (0) 2019.12.15
[알고리즘] 정렬4: merge sort  (0) 2019.12.15
[알고리즘] 정렬3: Insertion sort  (0) 2019.12.15
[알고리즘] 정렬2: bubble sort  (0) 2019.12.13
[알고리즘] 정렬1: selection sort  (0) 2019.12.13
반응형

Quick Sort

시간복잡도 : O(Nlog_2N) 이지만 최악의 경우는 마찬가지로 O(N^2)

퀵 정렬은 아주 빠른 속도를 나타낼뿐만 아니라 원리도 간단해서 많은 응용 분야에서 사용되고 있다.
퀵 정렬은 연속적인 분할에 의해서 정렬한다.

축(Pivot)값을 중심으로 왼쪽은 이 축값보다 작은 값으로 오른쪽은 모두 이 축값보다 큰 값을 배열시키는 것이다.
이렇게 하여 축값의 왼쪽과 오른쪽 부분을 각각 또다시 분할하고 하는 과정을 분할의 크기가 1이 될 때까지 반복하면 전체적으로는 정렬이 완료된다.

-리스트 마지막 인덱스의 값을 pivot으로 정함.
피봇을 뺀 나머지 배열에서 가장 양쪽 끝 인덱스를 저장. 왼쪽은 i, 오른쪽은 j (인덱스 2개 사용)
i는 오른쪽으로 가면서 해당 값이 pivot보다 작아야 한다. 큰 것이 발견되면 멈춤.
j는 왼쪽으로 가면서 해당 값이 pivot보다 커야 한다. 작은 것이 발견되면 멈춤.
i위치와 j위치의 값을 바꿈.
그런데, i, j가 만나게 되는 경우. (i>=j) 해당 위치가 pivot이 들어갈 자리.
i위치의 값과 pivot 값 swap한다.
pivot을 기준으로 왼쪽, 오른쪽으로 리스트를 나누어, 각각 처음부터 다시 소팅한다.

알고리즘

  1. 만약 n>1 이면
  2. 1 N 크기의 a 배열을 분할 하여 축값의 위치를 mid로 넘긴다.
  3. 2 퀵 정렬 알고리즘(a, mid)
  4. 3 퀵 정렬 알고리즘 (a+mid-1, N-mid-1)
void quick_sort(int a[], int n){
    int v, t;
    int i, j;
    if (n > 1){
        v = a[n - 1]; // v=축값. 마지막 노드값을 사용
        i = -1; 
        j = n - 1; 
        while (1){ // 분할
            while (a[++i] < v); // 왼쪽에서부터 축값보다 크거나 같은 값이 있는지?
            while (a[--j] > v){ // 오른쪽에서부터 축값보다 작거나 같은 값이 있는지? -> 가장작은값이 pivot이면?? index out range 위험 아래 체크 필요.
                if (j==0) break ;
            }
            if (i >= j) break; // i와 j의 위치가 뒤바뀌었으면 분할 끝
            t = a[i]; // 아니면 두 값을 바꿈
            a[i] = a[j];
            a[j] = t;
        }
        t = a[i]; // 축 값과 축값의 위치에 있는 값을 바꿈
        a[i] = a[n - 1];
        a[n - 1] = t;
        quick_sort(a, i); // 왼쪽 구간 퀵정렬
        quick_sort(a + i + 1, n - i - 1); // 오른쪽 구간 퀵정렬
    }
}

퀵 정렬은 난수 배열이나 반쯤 정렬된 배열에 대해서는 빠른 속도를 보이지만 이미 정렬된 배열이나 역순 배열에 대해서는 성능이 엄청나게 떨어진다.
퀵 정렬의 이상적인 경우는 분할이 정확하게 구간을 양분하는 것이다. 이 경우 재귀의 깊이는 logN이 되며 가장 빠른 속도를 나타낸다.
이렇게 퀵 정렬은 분할할 축값이 어느 정도 그 구간의 중앙을 나누느냐에 성능이 좌우된다.
재귀 호출로 인해서 내부 스택이 사용된다. 따라서 퀵 정렬이 속도가 빠른 반면에 메모리의 희생이 있다.
N이 커지면 커질수록 스택의 크기가 커지며 스택 오버플로우가 발생할 수 있다.

성능개선: 이미 정렬된 상태인지를 체크하는 것을 추가한다.

ex)

0,1,2,3,4,5,6,7,8 : 인덱스
5,3,8,4,9,1,6,2,7 : 값

qsort

  1. 피봇을 마지막 번째 노드 값으로 정하자. (보통 첫번째나 마지막번째로 정함.)
    남은 데이터의 양쪽 끝에서 가운데로 스캔해 나가면서 왼쪽에서는 피봇보다 큰 값을 찾으면 멈추고, 오른쪽에서는 피봇보다 작은 값을 찾으면 멈추고, 둘을 교환한다.

pivot=7, scan index=0, 7 start find over or below than pivot.
stop index=2(큰값발견),7(작은값발견) value 8>7>2 ;swap
0,1,2,3,4,5,6,7,8
5,3,2,4,9,1,6,8,7

pivot=7, stop index=4, 6 value 9>7>6 ;swap
0,1,2,3,4,5,6,7,8
5,3,2,4,6,1,9,8,7

pivot=7, stop index=6> 5 ; cross
stop. index=5, 4 인덱스가 교차되면 멈추고, 피봇(오른쪽 파트위치로 인덱스를 잡았으므로 right part에 속해야 한다. left part의 마지막 스캔 위치 인덱스6, 피봇보다 큰 수를 처음 발견한 지점에 들어가야 한다. )과 left last index(6)와 swap
0,1,2,3,4,5,6,7,8
5,3,2,4,6,1,7,8,9
피봇을 기준으로 좌우 분리가 끝남.
피봇 위치가 바뀌면 한 싸이클이 끝난 것임. (pivot 7을 기준으로 좌(low)우(high) 분리 완료)

  1. 좌우 파트("532461", "89")에 대해 각각 qsort 수행. 파트의 원소 개수가 1이면 스킵.
    2-2.
    0 1 (실제 인덱스는 7,8)
    8 9
    pivot=9, stop=N, 0. 왼쪽값을 찾지 못함. 즉, 모두 작다. 이미 피봇은 가장 우측이라 변경할 필요가 없다. 리턴

2-1.
0,1,2,3,4,5
5,3,2,4,6,1
new pivot=1, start 0, 4

pivot=1, stop 0, N; 왼쪽에서는 큰 값을 찾았는데, 오른쪽에서는 작은 값을 찾지 못함. left part last index=0과 swap
0,1,2,3,4,5
1,3,2,4,6,5

  1. 좌우 파트 수행 : "", "32465". 왼쪽 파트는 1개이하라 스킵. 오른쪽 파트 수행
    0 1 2 3 4 (실제 인덱스 : 1,2,3,4,5)
    3 2 4 6 5
    new pivot=5 ; start 0, 3
    pivot=5, stop=3>2.cross! last left index=3. change
    0 1 2 3 4 (실제 인덱스 : 1,2,3,4,5)
    3 2 4 5 6

  2. 좌우 파트 수행 : "3 2 4", "6" ; 오른쪽 파트는 스킵.
    0 1 2 (실제 인덱스 : 1,2,3)
    3 2 4
    pivot=4, stop=N, 1 no swap. break

  3. 좌우 파트 수행 "32", ""
    0 1 (실제 인덱스 : 1,2)
    3 2
    pivot=2, start=0,0
    pivot=2, stop=0, N ; swap with index 0
    0 1 (실제 인덱스 : 1,2)

2 3
6. 좌우 분할 ; "", "3" ; 모두 리턴

0,1,2,3,4,5,6,7,8 : 인덱스
1,2,3,4,5,6,7,8,9 : 값

vector<double>  QuickSort(vector<double>& vec1){
  double i =  0;
  double j = vec1.size()-2;
  double tmp;
  int pivotindex = vec1.size()-1  ;
  double pivot = vec1[pivotindex];
  if  ( vec1.size()<=1  )
    return vec1 ;
  cout <<  "QuickSort: ";
  printvector(vec1)  ;

  while  (i <= j)  {
    while  (vec1[i]  < pivot)
      i++;
    while  (vec1[j]  > pivot)
      j--;
    if  (i <= j)  {
      tmp = vec1[i];
      vec1[i]  = vec1[j];
     vec1[j]  = tmp;
     i++;
     j--;
    }
  }

  // pivot change
  vec1[pivotindex]  = vec1[i]  ;
  vec1[i]=pivot ;
  pivotindex=i ;

  cout <<  "pivotting: ";
  printvector(vec1)  ;

  if  (vec1.size()<=2  )
       return vec1 ;

    // partition
    vector<double> left_vec, right_vec ;
    vector<double>::iterator pivotiter = vec1.begin()+pivotindex ;
    copy(vec1.begin(), pivotiter, back_inserter(left_vec))  ;
    copy(pivotiter+1, vec1.end(), back_inserter(right_vec))  ;

    cout <<  "left: ";
    printvector(left_vec)  ;
    cout <<  "right: ";
    printvector(right_vec)  ;

    if  (left_vec.size()>0  )  {
        QuickSort(left_vec);
        copy(left_vec.begin(), left_vec.end(), vec1.begin())  ;
    }

    if  (right_vec.size()>0  )  {
        QuickSort(right_vec);
        copy(right_vec.begin(), right_vec.end(), pivotiter+1)  ;
    }
    return vec1;
}
반응형

Merge Sort

bottom-up으로 하위 그룹의 정렬부터 상위 그룹 정렬로 올라가며 정렬한다.
머지 정렬은 bottom-up으로 정렬 그룹이 2개 이하일 때를 종료 조건으로 하고, 하위 그룹의 머지 정렬이 끝나면 상위 그룹에서 두 개의 그룹을 합치는 것으로 동작한다.
작은 그룹들이 밑에서부터 미리 정렬되어 있기 때문에 정렬된 그룹간의 정렬이 빠르다는 것을 이용한다. linear하게 비교하면서 merge만 하면 바로 정렬된 상위 그룹을 만들 수 있다.
재귀함수를 사용하여 구현한다.

ex)
5 1 9 3 4 6 2 : 반씩 나눈다.
5 1 9 || 3 4 6 2 : 반
5 | 1 9 || 3 4 | 6 2 : 반
5 | 1 9 || 3 4 | 2 6 : 두 개 이하가 되면 정렬하고 리턴함.
1 5 9 || 2 3 4 6 : 두 그룹을 정렬한다. 리턴한다.
1 2 3 4 5 6 9 : 두 그룹을 정렬한다. 리턴한다.
완료

void mergeSort(int arr[], int size) {
 if (size > 2) {
  // 왼쪽 반, 오른쪽 반을 나누어 반복.
  mergeSort(arr, size / 2);
  mergeSort(arr + size / 2, size - size / 2);

  // 왼쪽, 오른쪽 반이 각각 정렬된 상태임. merge한다.
  int leftCursor = 0;
  int rightCursor = size / 2;
  int buff[50];
  int buffCursor = 0;
  // 두 그룹을 각각 스캐닝하면서 순서대로 기록. (어느 한쪽이 끝날때까지)
  while (leftCursor < size / 2 && rightCursor < size) {
    if (arr[leftCursor] < arr[rightCursor]) {
    buff[buffCursor++] = arr[leftCursor++];
   } else {
     buff[buffCursor++] = arr[rightCursor++];
   }
  }
  // 남은 한 그룹의 데이터를 append 
  for (int i = leftCursor ; i < size / 2 ; i++)
    buff[buffCursor++] = arr[i];
  for (int j = rightCursor ; j < size ; j++) 
    buff[buffCursor++] = arr[j];
  memcpy(arr, buff, size * sizeof(int));
 }else { // 원소 개수가 2개 이하인 경우, 비교하여 정렬한다.
  if (arr[0] > arr[1])
    swap(arr[0], arr[1]);
 }
}
반응형

Insertion Sort

: 삽입 정렬은 왼쪽 부터 항을 1개씩 정렬해나가면서 하나씩 항목을 추가해가면서 뒤에서부터 삽입해서 정렬되는 위치까지 삽입시키는 알고리즘이다.

--> 루프0
index 1을 왼쪽으로 한 칸씩 가면서 들어갈 자리를 찾는다.
index 0과 비교하여 작으면 위치를 바꾼다.
index 1까지 정렬 완료
--> 루프 1
index 2를 왼쪽으로 한 칸씩 가면서 들어갈 자리를 찾는다.
index 1과 비교 : 작으면 위치를 swap하고 계속 진행. 크면 break(루프 탈출)
index 0과 비교 : 작으면 위치를 swap하고 계속 진행. 크면 break(루프 탈출)
index 2까지 정렬 완료
--> 루프2
index 3를 왼쪽으로 한 칸씩 가면서 들어갈 자리를 찾는다.
index 2과 비교 : 작으면 위치를 swap하고 계속 진행. 크면 break(루프 탈출)
index 1과 비교 : 작으면 위치를 swap하고 계속 진행. 크면 break(루프 탈출)
index 0과 비교 : 작으면 위치를 swap하고 계속 진행. 크면 break(루프 탈출)
index 3까지 정렬 완료
...

ex)
loop i=1, j=0 ; index 1의 위치 찾기.
5 1 9 3 4 : index 1을 왼쪽을 비교하여 작으면 swap 크면 break 한다. swap
1 5 9 3 4 : 결과

loop i=2, j=1~0 ; index2의 위치 찾기
1 5 9 3 4 : index 2를 왼쪽을 비교하여 작으면 swap 크면 break 한다. break

loop i=3, j=2~0 ; index 3의 위치 찾기
1 5 9 3 4 : index 3를 왼쪽을 비교하여 작으면 swap 크면 break 한다. swap
1 5 3 9 4 : index 2를 왼쪽을 비교하여 작으면 swap 크면 break 한다. swap
1 3 5 9 4 : index 1를 왼쪽을 비교하여 작으면 swap 크면 break 한다. break
1 3 5 9 4 : 결과

loop i=4, j=3~0 ; index 4의 위치찾기
1 3 5 9 4 : index 4를 왼쪽을 비교하여 작으면 swap 크면 break 한다. swap
1 3 5 4 9 : index 3를 왼쪽을 비교하여 작으면 swap 크면 break 한다. swap
1 3 4 5 9 : index 2를 왼쪽을 비교하여 작으면 swap 크면 break 한다. break
1 3 4 5 9 : 결과

void insertion_sort(int arr[], int size) {
    for(int i = 1 ; i <= size - 1 ; i++) 
        for (int j = i-1 ; j >= 0 ; j--) 
            if(arr[j] > arr[j+1]) {
                // swap(arr[j], arr[j+1]);
                int t = arr[j] ;
                arr[j] = arr[j+1] ;
                arr[j+1] = t ;
            } 
            else
                continue;
} 

'Develop > C&CPP' 카테고리의 다른 글

[알고리즘] 정렬5: quick sort  (0) 2019.12.15
[알고리즘] 정렬4: merge sort  (0) 2019.12.15
[알고리즘] 정렬2: bubble sort  (0) 2019.12.13
[알고리즘] 정렬1: selection sort  (0) 2019.12.13
ASN.1c  (0) 2019.08.01
반응형

Bubble

복잡도: O(n^2)
이중 루프를 돌면서 두 개씩 쌍으로(옆에 있는 것끼리) 비교하여 순서를 맞춘다. (swap) 오른쪽으로 한 칸씩 이동하면서 반복한다.
위 작업을 마치면 마지막에는 가장 큰 값이 들어가게 된다.
다시 전 작업을 반복하는데, 끝 지점을 한 칸 왼쪽으로 이동시킨다. (가장 큰 값은 찾았으므로)

-> 루프0
index 0, 1 비교. (swap)
index 1, 2 비교.
...
index n-2, n-1(마지막인덱스) 비교.
결과 ; n-1인덱스에 가장 큰 값! ; 전체 n-1 번 비교

-> 루프1
index 0, 1 비교.
index 1, 2 비교.
...
index n-3, n-2비교. (마지막 인덱스를 1씩 감소)
결국 n-2에 다음으로 큰 값! ; 전체 n-2번 비교.
...

ex)
loop i=0. j=1-4
5 1 9 3 4 : 인덱스 0, 1을 비교하여 정렬 (before) swap
1 5 9 3 4 : 인덱스 1, 2를 비교하여 정렬
1 5 9 3 4 : 인덱스 2, 3를 비교하여 정렬 swap
1 5 3 9 4 : 인덱스 3, 4를 비교하여 정렬 swap
1 5 3 4 9 : 결과
마지막 인덱스에 가장 큰 값 찾기 완료.
loop i=1. j=1-3
1 5 3 4 9 : 인덱스 0, 1을 비교하여 정렬 (before)
1 5 3 4 9 : 인덱스 1, 2를 비교하여 정렬 swap
1 3 5 4 9 : 인덱스 2, 3를 비교하여 정렬 swap
1 3 4 5 9 : 결과
마지막 전 인덱스에 2번째 큰 값 찾기 완료.
...
(왼쪽 시작부터 버블 모양으로 비교를 한다. 이후 버블을 한 개씩 감소. )

void bubble_sort(int a[], int n){
    int i, j, t;
    for (i=0; i<n-1; i++) {
        for (j=1; j<n-i; j++){
           if (a[j-1] > a[j]){
            t = a[j-1];
            a[j-1] = a[j];
            a[j] = t;
            }
        }
    }
}
  • 성능개선안: swap 교환 횟수가 0이 되면 더 이상 할필요없으므로 리턴하면 된다.

void bubble_sort(int a[], int n){
    int i, j, t;
    for (i = 0; i < n - 1; i++) {
        int bchanged=0 ;
        for (j = 1; j < n - i; j++) // j=(1,10)
        {
            if (a[j - 1] > a[j]){
                t = a[j - 1];
                a[j - 1] = a[j];
                a[j] = t;
                bchanged=1 ;
            }
        }
        if (bchanged==0) break ;
    }
}

'Develop > C&CPP' 카테고리의 다른 글

[알고리즘] 정렬4: merge sort  (0) 2019.12.15
[알고리즘] 정렬3: Insertion sort  (0) 2019.12.15
[알고리즘] 정렬1: selection sort  (0) 2019.12.13
ASN.1c  (0) 2019.08.01
벡터 구조체 필드 기준으로 최대값 최소값 찾기  (0) 2019.05.31
반응형

정렬 알고리즘을 구현해 보고, 성능을 비교해 보자.
대략적으로 성능이 좋지 않은 순서대로 해 보겠다.

Selection Sort

복잡도: O(n^2)

아무 생각없이 바로 만들 수 있는 sorting 코드.
이중 루프를 돌면서 왼쪽부터 가장 작은 값을 찾아 넣음. (크면 바꾼다. swap 이것을 계속 반복하면 가장 작은 값이 index 0에 들어가게 된다.)
(일반적으로 성능 상관없이 정렬 작업할 때)

루프가 하나 끝나면 index 0가 최소값이 되고, 다음 루프로 index 1에 그 다음 작은 값이 들어가는 것을 반복한다.

-> 루프 0
index 0자리를 선택하여 나머지 전체에서 가장 작은 값을 넣고, (n-1번 비교)
index 0를 선택한 것을 index 1 부터 n-1까지 비교하면서 작은값이 있으면 swap. ; n-1인덱스에 가장 큰값이 이동됨.
-> 루프 1
index 1을 선택하여 그 다음 작은 값을 찾아 넣고. (n-2번 비교)
index 1을 선택한 것을 index 2부터 n-1까지 비교. ; n-2인덱스에 그 다음으로 큰 값이 이동됨.
...

ex)
loop i=0. j=1-4
5 1 9 3 4 : 인덱스 0, 1을 비교하여 대소위치 변경. swap
1 5 9 3 4 : 인덱스 0, 2를 비교하여 대소위치 변경
1 5 9 3 4 : 인덱스 0, 3를 비교하여 대소위치 변경
1 5 9 3 4 : 인덱스 0, 4를 비교하여 대소위치 변경
1 5 9 3 4 : 결과
인덱스0에 가장 작은 값 찾기 완료.
loop i=1. j=2-4
1 5 9 3 4 : 인덱스 1, 2을 비교하여 대소위치 변경
1 5 9 3 4 : 인덱스 1, 3를 비교하여 대소위치 변경 swap
1 3 9 5 4 : 인덱스 1, 4를 비교하여 대소위치 변경
1 3 9 5 4 : 결과
인덱스1에 2번째 작은 값 찾기 완료.
...
(왼쪽부터 위치를 하나 찍고 이후 나머지 것들과 모두 비교. 오른쪽으로 한 칸씩 이동)


void selection_sort(int arr[], int size) {
    for(int i = 0 ; i < size - 1 ; i++) 
        for (int j = i + 1 ; j < size ; j++) 
            if(arr[i] > arr[j]) {
                // swap(arr[i], arr[j]);
                int t = arr[i] ;
                arr[i] = arr[j] ;
                arr[j] = t ;
            }
}

'Develop > C&CPP' 카테고리의 다른 글

[알고리즘] 정렬3: Insertion sort  (0) 2019.12.15
[알고리즘] 정렬2: bubble sort  (0) 2019.12.13
ASN.1c  (0) 2019.08.01
벡터 구조체 필드 기준으로 최대값 최소값 찾기  (0) 2019.05.31
smart pointer 스마트포인터?  (0) 2018.07.19
반응형
hotkey_eclipse

HotKey Eclipse

  • 이클립스 단축키는 변경가능하여 가장 좋은 것은 설정에서 단축키를 찾는 것이 가장 정확하다.
    OS별로 다를 수 있음에 유의한다. Window , Mac , Linux 등.
    windows-preferences에서 Key로 검색
    Keys 화면내에서 검색하여 찾기
    예를 들면)
    comment : 주석관련
    find : 검색관련 , 다음 검색 등
    assist : 코드Assist (많이 찾는 Content Assist) 구조체 필드 확인, 메소드 목록 확인 등.
    import : 자동 import관련

빠르게 단축키를 보려면 ^+Shift+L 한 번 더 누르면 단축키 설정창을 띄운다. 다른 것 다 필요없고 이것만 기억해도 된다.

생각안나면 Ctrl+Shift+L 이것만 기억하자!!

+이클립스
-동일한 파일을 2개 창으로 보기
ctrl+{ ; 좌우로 보기 (ctrl+shift+{)
ctrl+_ ; 상하로 보기

-파일2개를 창2개로 보기
추가로 열 파일을 탭에서 드래그하여 원하는 윈도우 박스 위치에 놓는다.

컨쉽+O ; auto import
컨쉽+T ; 클래스 찾기
컨쉽+위/아래 ; 메소드 이동(위, 아래)
컨쉽+스페이스 ; 파라미터 보기
컨쉽+F ; 자동 코드 들여쓰기 정리. form feed.
컨+O ; 현재소스내에서 메소드나 필드로 이동 ; method
컨+T ; class tree보기/이동 상속관계 ; tree
컨+K ; 찾는 문자열 블록선택후, 연속으로 찾기. 반대방향은 쉽 추가.
컨+D ; delete line
컨+I ; auto indent (one line)

  • 가장 필요한 단축키.
    Code Assit
    추적
    돌아가기
    실행
    이전 커서위치로 이동.
    소스를 추적하여 쫒아가다가 다시 돌아갈 때 필요!!!

+요약
@+방향키 ; 이전 커서 위치로 이동!!! 소스추적하다가 되돌아갈때 필수!
^+Space ; 코드 파라미터 보기 (sysout 자동풀기) 리눅스에서는 @+/
^H ; 전체 검색
^K ; 다음 찾기. 이전찾기 ^+SHIFT+K
F3 or ^클릭 ; 추적 go to definition
^+F11 ; 실행
^F6 ; 이전 에디터창(소스).
^Q ; 소스 마지막 수정위치로 이동
^+SHIFT+/ ; 블록 주석처리
^+ / ; 주석처리
^+SHIFT+F ; 코드 정리

+이클립스(MAC)
(@대신Com)+방향키 ; 이전 커서 위치로 이동
(Com추가)+^+Space ; 코드 파라미터 보기
F3 or ^+클릭 ; 추적
(FN추가)+^+F11 ; 실행
^F6 ; 이전 에디터창(소스).
^Q ; 소스 마지막 수정위치로 이동
^H ; 전체 검색
^K ; 다음 찾기. 이전찾기 ^+SHIFT+K

단축키가 안먹는다면 다른 프로그램 단축키와 충돌이 났거나 다를 수 있어서 다른 단축키로 바꿔보자.
언제든 설정에서 원하는 단축키를 지정할 수 있고, 현재 단축키 설정도 확인 가능하니 처음에는 꼭 확인하는 것을 권장한다.

Author: crazyj7@gmail.com

'Develop > Java' 카테고리의 다른 글

gradle2 API server  (0) 2021.11.13
gradle1 기초  (0) 2021.11.13
Short URL(단축URL) API  (1) 2019.11.07
[JavaScript] 스탑와치 밀리초/StopWatch milliseconds  (0) 2019.08.27
Java RSA 간단한 비대칭키 암호 서명 검증 테스트  (0) 2019.08.14
반응형
tomcat_setup

Tomcat 8 install

Ubuntu 기준으로 tomcat8 설치하기

JDK8

$ apt-cache search openjdk-8
$ apt-get install openjdk-8-jdk
$ java -version
openjdk version 1.8.0_222

설치 경로 확인

$ upate-alternatives --list java
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
$ cd /usr/lib
$ ln -s jvm/java-8-openjdk-amd64 java
$ ls /usr/lib/java

tomcat8

tomcat은 패키지를 apt-get으로 설치하면 자동으로 설정이 되는 장점이 있지만, 수동으로 받아서 설치하는 것이 좋다. (개인 취향)
수동으로 하는 것은 설치 경로나 구성 등을 본인에 맞게 할 수 있다.

간략 버전 (빠른 설치)

sudo apt-get install tomcat8
ufw allow 8080
service tomcat8 start
끝

수동 설치
http://tomcat.apache.org
홈페이지에서 원하는 버전의 다운로드 URL을 복사한다.

# cd /usr
# wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.9/bin/apache-tomcat-8.5.9.tar.gz
# tar xvfz apache*.gz
# ln -s apache-tomcat-8.5.9 tomcat
# cd /usr/tomcat/bin
# ./version.sh
Apache Tomcat/8.5.9

환경 설정

  • 방화벽 오픈
    ufw allow 8080
  • 환경 변수
$ vi /etc/profile
export JAVA_HOME=/usr/lib/java
export CATALINA_HOME=/usr/tomcat
export CLASSPATH=.:$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib/jsp-api.jar:$CATALINA_HOME/lib/servlet-api.jar 

$ source /etc/profile
  • 구동 테스트
    cd /usr/tomcat/bin
    ./startup.sh
    netstat -ant | grep 8080
    ps -ef | grep tomcat

브라우저에서 http://IP:8080 으로 접속하여 페이지가 뜨는지 확인한다.

  • 테스트 종료
    ./shutdown.sh

서비스 등록

  • 계정 생성
groupadd tomcat
useradd -M -s /bin/nologin -g tomcat -d /usr/tomcat tomcat
cd /usr/
chown -R tomcat.tomcat apache-tomcat-8.5.9
  • 서비스 등록
root@blockchain:/etc/systemd/system# cat tomcat.service 
# Systemd unit file for tomcat
[Unit]
Description=Apache Tomcat Web Application Container
After=syslog.target network.target

[Service]
Type=forking

Environment="JAVA_HOME=/usr/lib/java"
Environment="CATALINA_PID=/usr/tomcat/temp/tomcat.pid"
Environment="CATALINA_HOME=/usr/tomcat"
Environment="CATALINA_BASE=/usr/tomcat"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"

ExecStart=/usr/tomcat/bin/startup.sh
ExecStop=/usr/tomcat/bin/shutdown.sh

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

위와 같이 파일을 작성하고
systemctl daemon-reload

서비스 구동

service tomcat status
service tomcat start

부팅시 자동시작 스크립트

/etc/init.d에 tomcat 파일을 아래와 같이 만들고
chomd 755 tomcat으로 권한을 설정한다.
JAVA_HOME, CATALINA_HOME, tomcat 계정, 디렉터리를 잘 설정한다.

#!/bin/sh
#
# /etc/init.d/tomcat -- startup script for the Tomcat 8 servlet engine
#
# Modified init-Script from Ubuntu Tomcat init-script
#
#
### BEGIN INIT INFO
# Provides:          tomcat
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Should-Start:      $named
# Should-Stop:       $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start Tomcat.
# Description:       Start the Tomcat servlet engine.
### END INIT INFO

set -e

PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/tomcat
NAME=tomcat
DESC="Tomcat servlet engine"
DEFAULT=/etc/default/$NAME
JVM_TMP=/tmp/tomcat-tmp

if [ `id -u` -ne 0 ]; then
        echo "You need root privileges to run this script"
        exit 1
fi

# Make sure tomcat is started with system locale
if [ -r /etc/default/locale ]; then
        . /etc/default/locale
        export LANG
fi

. /lib/lsb/init-functions

if [ -r /etc/default/rcS ]; then
        . /etc/default/rcS
fi


# The following variables can be overwritten in $DEFAULT

# Run Tomcat 8 as this user ID and group ID
TOMCAT_USER=tomcat
TOMCAT_GROUP=tomcat

# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not
# defined in $DEFAULT)
JDK_DIRS="/usr/lib/java"

# Look for the right JVM to use
for jdir in $JDK_DIRS; do
    if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then
        JAVA_HOME="$jdir"
    fi
done

export JAVA_HOME=/usr/lib/java

# Directory where the Tomcat binary distribution resides
CATALINA_HOME=/usr/$NAME

# Directory for per-instance configuration files and webapps
CATALINA_BASE=/usr/$NAME

# Use the Java security manager? (yes/no)
TOMCAT_SECURITY=no

# Default Java options
# Set java.awt.headless=true if JAVA_OPTS is not set so the
# Xalan XSL transformer can work without X11 display on JDK 1.4+
# It also looks like the default heap size of 64M is not enough for most cases
# so the maximum heap size is set to 128M
if [ -z "$JAVA_OPTS" ]; then
        JAVA_OPTS="-Djava.awt.headless=true -Xmx128M"
fi

# End of variables that can be overwritten in $DEFAULT

# overwrite settings from default file
if [ -f "$DEFAULT" ]; then
        . "$DEFAULT"
fi

if [ ! -f "$CATALINA_HOME/bin/bootstrap.jar" ]; then
        log_failure_msg "$NAME is not installed"
        exit 1
fi

POLICY_CACHE="$CATALINA_BASE/work/catalina.policy"

if [ -z "$CATALINA_TMPDIR" ]; then
        CATALINA_TMPDIR="$JVM_TMP"
fi

# Set the JSP compiler if set in the tomcat.default file
if [ -n "$JSP_COMPILER" ]; then
        JAVA_OPTS="$JAVA_OPTS -Dbuild.compiler=\"$JSP_COMPILER\""
fi

SECURITY=""
if [ "$TOMCAT_SECURITY" = "yes" ]; then
        SECURITY="-security"
fi

# Define other required variables
CATALINA_PID="/var/run/$NAME.pid"
CATALINA_SH="$CATALINA_HOME/bin/catalina.sh"

# Look for Java Secure Sockets Extension (JSSE) JARs
if [ -z "${JSSE_HOME}" -a -r "${JAVA_HOME}/jre/lib/jsse.jar" ]; then
    JSSE_HOME="${JAVA_HOME}/jre/"
fi

catalina_sh() {
        # Escape any double quotes in the value of JAVA_OPTS
        JAVA_OPTS="$(echo $JAVA_OPTS | sed 's/\"/\\\"/g')"

        AUTHBIND_COMMAND=""
        if [ "$AUTHBIND" = "yes" -a "$1" = "start" ]; then
                JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
                AUTHBIND_COMMAND="/usr/bin/authbind --deep /bin/bash -c "
        fi

        # Define the command to run Tomcat's catalina.sh as a daemon
        # set -a tells sh to export assigned variables to spawned shells.
        TOMCAT_SH="set -a; JAVA_HOME=\"$JAVA_HOME\"; source \"$DEFAULT\"; \
                CATALINA_HOME=\"$CATALINA_HOME\"; \
                CATALINA_BASE=\"$CATALINA_BASE\"; \
                JAVA_OPTS=\"$JAVA_OPTS\"; \
                CATALINA_PID=\"$CATALINA_PID\"; \
                CATALINA_TMPDIR=\"$CATALINA_TMPDIR\"; \
                LANG=\"$LANG\"; JSSE_HOME=\"$JSSE_HOME\"; \
                cd \"$CATALINA_BASE\"; \
                \"$CATALINA_SH\" $@"

        if [ "$AUTHBIND" = "yes" -a "$1" = "start" ]; then
                TOMCAT_SH="'$TOMCAT_SH'"
        fi

        # Run the catalina.sh script as a daemon
        set +e
        touch "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out
        chown $TOMCAT_USER "$CATALINA_PID" "$CATALINA_BASE"/logs/catalina.out
        start-stop-daemon --start -b -u "$TOMCAT_USER" -g "$TOMCAT_GROUP" \
                -c "$TOMCAT_USER" -d "$CATALINA_TMPDIR" \
                -x /bin/bash -- -c "$AUTHBIND_COMMAND $TOMCAT_SH"
        status="$?"
        set +a -e
        return $status
}

case "$1" in
  start)
        if [ -z "$JAVA_HOME" ]; then
                log_failure_msg "no JDK found - please set JAVA_HOME"
                exit 1
        fi

        if [ ! -d "$CATALINA_BASE/conf" ]; then
                log_failure_msg "invalid CATALINA_BASE: $CATALINA_BASE"
                exit 1
        fi

        log_daemon_msg "Starting $DESC" "$NAME"
        if start-stop-daemon --test --start --pidfile "$CATALINA_PID" \
                --user $TOMCAT_USER --exec "$JAVA_HOME/bin/java" \
                >/dev/null; then

                # Regenerate POLICY_CACHE file
                umask 022
                echo "// AUTO-GENERATED FILE from /opt/tomcat/" \
                        > "$POLICY_CACHE"
                echo ""  >> "$POLICY_CACHE"
                cat $CATALINA_BASE/conf/*.policy \
                        >> "$POLICY_CACHE"

                # Remove / recreate JVM_TMP directory
                rm -rf "$JVM_TMP"
                mkdir -p "$JVM_TMP" || {
                        log_failure_msg "could not create JVM temporary directory"
                        exit 1
                }
                chown $TOMCAT_USER "$JVM_TMP"

                catalina_sh start $SECURITY
                sleep 5
                if start-stop-daemon --test --start --pidfile "$CATALINA_PID" \
                        --user $TOMCAT_USER --exec "$JAVA_HOME/bin/java" \
                        >/dev/null; then
                        if [ -f "$CATALINA_PID" ]; then
                                rm -f "$CATALINA_PID"
                        fi
                        log_end_msg 1
                else
                        log_end_msg 0
                fi
        else
                log_progress_msg "(already running)"
                log_end_msg 0
        fi
        ;;
  stop)
        log_daemon_msg "Stopping $DESC" "$NAME"

        set +e
        if [ -f "$CATALINA_PID" ]; then
                start-stop-daemon --stop --pidfile "$CATALINA_PID" \
                        --user "$TOMCAT_USER" \
                        --retry=TERM/20/KILL/5 >/dev/null
                if [ $? -eq 1 ]; then
                        log_progress_msg "$DESC is not running but pid file exists, cleaning up"
                elif [ $? -eq 3 ]; then
                        PID="`cat $CATALINA_PID`"
                        log_failure_msg "Failed to stop $NAME (pid $PID)"
                        exit 1
                fi
                rm -f "$CATALINA_PID"
                rm -rf "$JVM_TMP"
        else
                log_progress_msg "(not running)"
        fi
        log_end_msg 0
        set -e
        ;;
   status)
        set +e
        start-stop-daemon --test --start --pidfile "$CATALINA_PID" \
                --user $TOMCAT_USER --exec "$JAVA_HOME/bin/java" \
                >/dev/null 2>&1
        if [ "$?" = "0" ]; then

                if [ -f "$CATALINA_PID" ]; then
                    log_success_msg "$DESC is not running, but pid file exists."
                        exit 1
                else
                    log_success_msg "$DESC is not running."
                        exit 3
                fi
        else
                log_success_msg "$DESC is running with pid `cat $CATALINA_PID`"
        fi
        set -e
        ;;
  restart|force-reload)
        if [ -f "$CATALINA_PID" ]; then
                $0 stop
                sleep 1
        fi
        $0 start
        ;;
  try-restart)
        if start-stop-daemon --test --start --pidfile "$CATALINA_PID" \
                --user $TOMCAT_USER --exec "$JAVA_HOME/bin/java" \
                >/dev/null; then
                $0 start
        fi
        ;;
  *)
        log_success_msg "Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
        exit 1
        ;;
esac

exit 0

Author: crazyj7@gmail.com

'Develop > Linux_Unix' 카테고리의 다른 글

[도커] tomcat, mariadb 환경 war hang/slow  (0) 2021.04.28
Bash Tip 작업속도를 빠르게  (0) 2021.03.03
리눅스 백그라운드 실행(터미널종료에도)  (1) 2021.02.23
Git 사용법_요약  (0) 2019.12.16
VI 사용법  (0) 2015.06.02
반응형
mysql_setup

MySQL 5.7

타임존 설정

타임존 선택 수동으로 설정하는 방식

ls /usr/share/zoneinfo
여기에서 원하는 지역을 디렉터리 구조 내부를 탐색하여 찾는다.
ls /usr/share/zoneinfo/Asia/Seoul

현재설정
$ ll /etc/localtime
/etc/localtime -> /usr/share/zoneinfo/America/New_York
$ date
Thu Nov 7 20:48:33 EST 2019

다음과 같이 변경
$ sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
$ date
Fri Nov 8 10:55:06 KST 2019

사실 타임존 선택은 더 간단하게 “tzselect” 커맨드로 하면 메뉴를 골라 쉽게 설정할 수 도 있다.

$ tzselect

시간 동기화

시간이 틀리면 여러가지 문제가 발생하니 먼저 시간을 동기화하자.

sudo apt-get install ntp

vi /etc/ntp/conf
server 1.kr.pool.ntp.org
server 1.asia.pool.ntp.org
server time.bora.net

sudo service ntp restart
sudo ntpq -p

설치 (Ubuntu 기준)

-기존 설치된 것 삭제

apt list | grep mysql-server
버전 확인
sudo apt-get purge mysql-server
sudo apt-get purge mysql-common

설치 데이터 삭제
아래 경로 반드시 확인 필요!
rm -rf /var/log/mysql
rm -rf /var/log/mysql.*
rm -rf /var/lib/mysql
rm -rf /etc/mysql
  • 패키지 검색

  • sudo apt-get update

  • sudo apt-cache search mysql-server
    image

  • 설치

  • sudo apt-get install mysql-server-5.7
    image

$ mysql --version
5.7.27
$ vi /etc/mysql/mysql.conf.d/mysqld.cnf
port 번호 변경 (옵션)
$ service mysql restart

관리자 패스워드 설정

수동으로 패스워드 설정 방법

루트로 mysql을 실행한다.
$ sudo mysql -u root 
패스워드 없이 로그인 됨.
> alter user 'root'@'localhost' identified with mysql_native_password by '패스워드';
> flush privileges ;
> exit
$ service mysql restart

일반계정으로 전환하여 로그인 (로컬)
$ mysql -u root -p

간단하게 커맨드로 설정하는 방법

루트로 로그인하여
$ mysqladmin -u root -p password

계정 생성

로컬 접속

> create database test character set utf8 collate utf8_bin ;  # test DB를 만들어서 아래 권한 부여 (옵션)

> use mysql ;
> insert into user(host, user, authentication_string, ssl_cipher,
 x509_issuer, x509_subject) 
 values('localhost', '계정', password('패스워드'), '', '', ''); 
> flush privileges ;
> grant all privileges on DB명.* to 계정@localhost;
> flush privileges ;

빈 값 필드들을 빼보니 쿼리가 실패하였다. grant전에 flush를 안해주면 쿼리가 실패한다. 위에 나온대로 하는 게 좋다.

원격 접속

> 위 로컬 접속에서 localhost를 %로만 바꿔준다. 

더 간단한 방법

> craete user '계정'@'localhost' identified by '패스워드' 
   password expire never ;
> grant all privileges on DB명.* to 계정@localhost;

Author: crazyj7@gmail.com

+ Recent posts