3월11일 일본관동대지진

3월 11일 일본관동대지진 - 나의 경험담 -

3월 11일 오후 10시경
학교는 이미 봄방학에 들어갔지만, 
학교의 컴퓨터실에서 코딩을 하고있었다.
오후 2시 30분경쯤이었을까 컴퓨터화면이 흔들거리기 시작했다.
내가 사는 이바라키현 츠쿠바시는 비교적 지반이 튼튼하다고 알고있지만
가끔씩 작은 지진이 일어나곤한다.
여느때처럼 작은 지진이구나... 라고생각했다.
하지만 점점 진동은 심해지고, 중심을 제대로 잡을 수 없을 정도로 심하게 흔들거렸다.
건물이 너무 심하게 흔들려서 앉아있던 의자에서 살짝 옆으로 넘어져버렸다.
일어나려고했지만 건물이 너무 심하게 흔들거려서 몇초간 주저앉아있었던것같다.
순간, 건물밖으로 나각야겠다는 생각이 번뜩들었다.
죽을지도 모른다는 생각이 이런거구나 하는 느낌이 이제는 뭔지 알것같다.
학교건물밖으로 나가자 이미 많은 사람들이 나와있었다.
도서관, 연구실에 있던 사람들도 일제히 밖으로 뛰쳐나오고 있었다.
연구실건물의 창문이 깨져서 떨어지고,
바닥의 타일은 갈라져서 나뒹굴었다.

휴대전화는 사용불가. 정전이 일어난 탓일것이다.
이런 긴급상황에는 휴대전화가 무용지물이 된다는걸 깨달았다.

집으로 돌아왔다. 다행히 집은 무너져있지 않았다.
하지만, 당장 내일 먹을 식량이 없었다.
수도, 전기, 가스 모두 사용불가능했다.
점점 정신이 없어진다.
편의점이나 슈퍼마켓, 음식점 죄다 쓸모없게 되었다.
신호등도 꺼졌다. 가로등도 꺼졌다.
당장 촛불이나 손전등이 있을리가 없다.

도대체 어떻게 된건지 알 수 있는길은 학교에서 틀어주는 라디오방송.
라디오에서 흘러나오는 뉴스를 듣고, 상황파악을 했다.

하지만, 큰 도움이 되질 않는다.

사람들은 불안해하고, 점점 밤은 찾아온다...

3월 11일 밤

도대체가 잠을 제대로 잘 수가 없다.
간헐적으로 오는 여진으로 선잠을 자다 깨는 상황이 반복된다.

3월 12일 오전

같은 유학생의 집을 찾아가보기로 했다.
선배의 집에는 이미 몇몇 유학생이 피난와있었다.
다행이 선배집에는 수도와 전기가 사용가능한 상태다.
5명인지 6명인지 제대로 기억은 안 나지만,
그 선배의 집에서 머물면서 뉴스에 촉각을 곤두세웠다.
이바라키현은 비교적 피해가 적은편이었다.
후쿠시마현과 이와테현은 정말 지옥이었다.
쓰나미로 마을이 통째로 쓸려나가고, 핵발전소가 터지고...

3월 13일

이바라키현은 후쿠시마현의 바로 남쪽에 위치하고있다.
후쿠시마현에서 문제가되는 핵발전소의 폭발로 매우 불안했다.
하지만, 시간이 흐름에 따라 침착해 질 수 있었다.

이후로 지금까지 상황을 지켜보고 있다.
유학생 대부분이 모두 한국으로 돌아갔다.
이유는 방사선노출이 걱정되어서 일것이다.
하지만, 나는 별로 걱정되지 않는다. 적어도 지금은 그렇다.
안전불감증은 아니지만, 뭐랄까 묘하게 안전한 느낌이 든다.
오히려 뉴스를 보며 침착하게 대응하는게 더 현명할지도 모른다.
남이 하니까 따라하고 남이 가니까 따라가고가 아니라,
내가 위험하다고 판단될 때, 그 때 피신을 가더라도 가는것이다.

좀 더 지켜보자...

배열을 인수로 받는 함수내에서 sizeof 가 제대로 작동하지 않는 이유에 대하여

배열 A 의 길이는 흔히

와 같이 구하고는 한다.
 하지만, 배열을 인수로 받는 함수내에서 배열 A 의 길이를 구하고자 한다면 이야기가 달라진다. 예를들어,

와 같은 코드는 제대로 작동하지 않는다.

 위와같이 배열의 포인터를 인수로 받는경우, 컴파일러는 함수내의 포인터를 배열이라고 인식하지 않고 단순히 포인터로 인식한다.
따라서 포인터의 크기를 인트형의 크기로 나누는 작업을 하는 오류를 일으키게 되는것이다.
 함수내에서 배열의 길이를 구하고자 한다면, 함수를 호출하는 쪽에서 함수의 길이를 계산하여 그 값을 인자값으로 넘겨주는 방법이 제일 간단하다.
 C++나 JAVA와 같은 언어를 사용한다면, STL이나 컬렉션을 이용하여 이런 문제를 해결할 수 있지만, C언어에서는 그냥 인자값으로 배열과 배열의 길이를 같이 넘겨주는게 가장 편한것 같다.

[알고리즘&자료구조] 힙 구조 & 힙 정렬

 정렬알고리즘에는 다양한 종류가 있지만, 힙정렬 알고리즘은 힙구조라는 매우 유용한 자료구조를 이용하고있다. 힙구조는 힙정렬뿐만 아니라, 우선순위큐를 구현하는데에도 응용된다. 힙정렬을 구현하기 위해서는 먼저, 힙구조를 이해할 필요가 있다. 힙구조에는 최대힙과 최소힙이 있는데, 최대힙을 구현하는것으로 최소힙은 생략하겠다.
 먼저, 최대힙에 대해서 알아보자. 최대힙이란 기본적으로 2진트리의 모양새를 취한다. 부모노드가 항상 자식노드보다 큰 값을 가지는 구조를 만족한다면 최대힙이다. 따라서 최대힙의 최상위루트의 값이 트리전체의 요소중 최대값임을 알 수있다.

 최대힙을 이용하여 힙정렬을 수행하는 기본원리는 다음과 같다.
 1. 먼저 최대힙을 구성한다.
 2. 최대힙의 최상위루트값(최대값)을 수열의 맨뒤로 보내고 수열의 길이를 하나 줄인다.
 3. 과정2로 인해 수열이 변경되었으므로, 변경된 수열에 대해서 다시 최대힙을 구성한다.
 4. 과정1 ~ 과정3 을 수열의 길이가 1이 될 때 까지 반복한다.
최대힙은 그 이름에서도 알 수 있듯이 최상위루트값이 수열의 최대값이므로 최대값을 계속 추출해내는 작업을 통해서 수열을 정렬하는 것이다.
( 최대힙이 2진트리의 모양새를 하고있다는것은 어디까지나 가상이고, 실제로는 배열에서 모든 처리를 수행하게된다. 즉, 실제 트리구조에서처럼 포인터를 갖는 데이터구조를 만들 필요는 없다.)

 힙정렬을 구현하기에 앞서, 최대힙을 구성해야하는데 최대힙은 기본적으로 2진트리의 모양을 하고 있으므로 2진트리의 기본적인 성질을 알아보자.
2진트리는 자식노드를 단 2개
(왼쪽자식과 오른쪽자식)만을가지는 트리구조이다. 배열에서의 인덱스 k 번째요소를 k노드라고 하자. 노드k의 왼쪽자식은 노드(2*k+1) 이고, 오른쪽자식은 노드(2*k+2) 이다. (오른자식을 노드 3k 라고하는것은 적절하지 않다.)  또, 부모노드는 (int)(k*0.5)-1이다. 임의의 노드k 를 기준으로 왼쪽자식노드, 오른쪽자식노드, 부모노드의 인덱스가 모두 계산가능함을 알 수 있다. 지금까지 논의된 구체적인 노드의 인덱스값은 배열의 인덱스값이 0부터 시작되는 환경을 기준으로 했다. 예를들면 C, C++, JAVA 와 같은 언어는 배열이 인덱스0부터 시작된다. 마지막으로, 배열의 요소수가 n개인경우 자식을 적어도 하나이상 가지는 노드는 [0, ( int )( n * 0.5 ) - 1)]이고, 자식을 가지지 않는 리프노드는 나머지 범위가 된다.

 이제, 위의 성질들을 바탕으로하여 최대힙을 구성하는 방법을 생각해 보자.
 전체트리는 부분트리로 구성된다고 생각할 때, 부분트리가 모두 최대힙특성을 가지게 하면 전체트리는 자연스럽게 최대힙특성을 가지게 된다. 자식을 가지지 않는 리프노드는 그 자체로 최대힙특성(상위루트가 자식노드보다 큰 값을 가지는 특성)을 가진다. 따라서, 자식을 하나이상 가지는 노드들에 대해서 최대힙특성을 가지게끔하는 조작을 수행하도록 한다. 이 때, 자식노드와 상위노드의 값이 교환됨에 의해 자식노드를 상위노드로 하는 트리가 최대힙특성을 위반하게될 가능성이 생기므로 변경한 자식노드에 대해 재귀적적으로 최대힙특성을 유지하도록 하여야한다.
 노드k 를 최상위 루트로하는 트리에대하여 최대힙특성을 가지도록 하는 함수는 아래와같다.




 위의 Heapify 함수에서 HeapSize 는 현재 고려중인 수열의 길이를 의미하며, 힙정렬을 수행할때 필요한 인수값이므로 지금은 넘어가도 좋다. 노드k와 노드k의 왼자식, 오른자식중 가장 큰 값의 인덱스를 찾아서 상위노드값과 교환한다. 그리고 교환에의해 최대힙특성이 위반될 가능성이 생겼으므로, 변경된 노드에 대해서 재귀적으로 Heapify 함수를 호출하고있다.

 다음은 위의
Heapify 함수를 이용하여 주어진 수열을 최대힙으로 만드는 BuildHeap 함수를 살펴보자.
 



  BuildHeap 함수는 적어도 하나이상의 자식을 가지는 노드에 대해서 Heapify 함수를 호출하여 최대힙특성을 만족시키도록 하고있다. 자식을 가지는 노드의 호출순서가 중요한다. 자식을 가지는 노드중에서도 가장 아래쪽 노드부터 트리의 윗쪽 노드의 방향으로 호출하여야 함에 주의하자.

그럼,  최대힙구조를 이용하여 힙소트를 수행해보자. 최대힙구조를 이용하여 힙소트를 수행하는 방법에 대해서는 이 글의 서두에서 한 번 언급이 되었지만 아래에서 다시 한 번 더 확인하자.
 최대힙을 이용하여 힙정렬을 수행하는 기본원리는 다음과 같다.
 1. 먼저 최대힙을 구성한다.
 2. 최대힙의 최상위루트값(최대값)을 수열의 맨뒤로 보내고 수열의 길이를 하나 줄인다.
 3. 과정2로 인해 수열이 변경되었으므로, 변경된 수열에 대해서 다시 최대힙을 구성한다.
 4. 과정1 ~ 과정3 을 수열의 길이가 1이 될 때 까지 반복한다.

 힙소트의 소스코드는 아래와같다.



 HeapSize 는 수열의 길이로 초기화한다음, 최대힙구조에서 최상위루트값을 추출함에 따라서 하나씩 그 값이 줄어들게 하고있다.

 힙소트가 비록 O(n*log(n)) 의 비용으로 정렬이 가능한 매력적인 알고리즘이지만, 일반적으로 Quick Sort 알고리즘이 보다 빠른것으로 알려져있다. 하지만, 힙소트에 이용되는 힙구조는 우선순위큐에의 응용 등 알아두면 유용한 자료구조이므로 소개하였다.
prev 1 ··· 3 4 5 6 7 next