카테고리 보관물: Programming

Heap sort (힙 정렬)

Heap sort는 root node에 항상 제일 작은 값이나 제일 큰 값이 오도록 heap tree를 구성해서 정렬하는 방법이다. Heap tree의 root에 최소 값이 오도록 구현하면 min heap tree, 최대 값이 오도록 하면 max heap tree라 한다. Heap tree를 구성하는 방법에 대해서는 별도의 포스트로 다루고 여기서는 max heap으로 오름차순 정렬하는 과정을 설명한다.

Heap sort는 한번 heap tree를 구성한 다음에는, 어떤 값이 제자리를 찾는데 소요되는 시간이 짧다는 점을 이용한다. 부모와 자식노드의 값에 따라 완전 이진트리로 구성하므로, 처음 한 번 heap tree를 구성할 때 O(N/2)만큼 소요된 이후에는, heap tree가 구성된 상태에서는 어떤 노드의 제자리를 찾는데 O(log N) 만큼이 소요된다.

Heap sort 과정을 정리하면 다음과 같다.

1. Heap tree를 만든다.
2. 제일 마지막 노드를 root와 바꿔서 heap tree른 망가뜨린다. 
   이때, root에 있던 최대값은 배열의 마지막 위치로 옮겨진다.
3. Heap tree를 구성하는 배열 크기를 하나 줄여서 옮겨진 최대값을 heap tree에서 제외시킨다.
4. 다시 heap tree가 되도록 새로운 root의 자리를 찾아 준다.
5. 위의 2, 3, 4번 과정을 배열의 크기가 1이 될때 까지 반복한다.

언뜻 잘 이해가 안 갈수도 있는데, 모종의 과정을 거치고 나면 root (배열의 0번 index)에 최대값이 오게되는 마법의 tree가 있고 이것의 root를 싹둑싹둑 자를때마다 남아있는 것들 중 제일 큰값이 root에 올라오는 것을 상상해보면 도움이 될지도 모르겠다. Tree라고 하면 일반적으로 왼쪽과 오른쪽 자식노드에 대한 pointer를 가지는 형태를 떠올리게 되니까 배열로 표현된 tree가 혼동스러울 수도 있겠는데, 완전 이진 트리인 경우에는 배열안에 원소들이 차례대로 들어 있다고 가정할 때 왼쪽/오른쪽 자식 node의 위치를 다음의 계산식으로 구할 수 있다.

왼쪽 자식 index = (2 * 부모 node index) + 1
오른쪽 자식 index = 왼쪽 자식 index + 1

그리고 하나라도 자식이 있는 부모 node들의 index도 구할 수 있다.

부모 node들 = [0 부터 floor(배열 크기 / 2) - 1 까지]

* floor() : 소숫점 버림
예) 배열크기가 10 이면 부모 node는 0, 1, 2, 3, 4가 된다.

어떤 배열이 다음의 순서일 때 이를 heap sort하는 과정의 예를 들어 살펴보자.

{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}

1. “Heap tree를 만든다.”

Max heap을 가정하므로, 위의 배열로 max heap tree를 만들면 다음과 같다. 대괄호([ ]) 안에 있는 숫자는 배열상의  index를 의미한다.

예제의 경우, 이미 “모든 서브트리의 부모가 가진 값이 자식보다 크다”는 max heap tree 조건을 만족하기 때문에 배열 안에서의 순서가 변경되지 않는다. 다른 경우에 heap tree를 생성하는 절차는 나중에 설명하도록 하고 지금은 꼼수 같겠지만 일단 그냥 넘어가자. 위 그림에서 색칠된 node들은 자식들을 가지는 부모 node들인데, 앞서 설명한 부모 node들의 index를 구하는 공식에 의해서 얻을 수 있다. 이 예제에서는 잘 보이지 않지만, 부모 node들의 index를 구하는 것은 heap tree를 구성할 때 중요하다. 이 부분도 별도의 포스팅으로 따로 설명한다.

2. “제일 마지막 node를 root와 바꿔서 heap tree를 망가뜨린다.”

“아니 왜?” 하는 생각이 들 수도 있을 텐데, root에는 최대값이 들어 있으므로 제일 마지막 node와 swap하면 root에 있던 값은 오름 차순 정렬일 때의 자기 자리를 찾아가는 샘이 된다.

3. “Heap tree를 구성하는 배열의 크기를 하나 줄인다.”

이전의 root였던 10은 제자리를 찾았으니 이제 배열의 크기를 하나 줄여서 index 0 ~ 8까지가 배열이라고 가정한다. 배열 그림을 보면 정렬되어가는 모습이 보일 것이다.

4. “다시 heap tree가 되도록 새로운 root의 자리를 찾아 준다.”

얼떨결에 새로운 root가 된 node는 이제 자기 있을 곳을 찾아가야 한다. 자식 node들과의 크기를 비교해서 둘 중 큰 자식과 swap하면서 원래 있어야 할 곳을 찾아간다. 완전 이진 트리의 장점을 살려서 O(log N)의 비교 연산만에 자기 자리를 찾을 수 있다. 이 과정에서 노드들간의 swap이 일어나고 root에는 다시 최소 혹은 최대값이 오게된다.

Root였던 ‘1’은 자식들 중 더 큰 왼쪽 자식인 ‘9’와 자리를 바꾼다.

여전히 max heap tree를 만족하지 못하므로 ‘7’, ‘6’ 중 큰 자식인 ‘7’과 자리를 바꾼다.

마지막으로 ‘3’, ‘2’ 중 큰 자식인 ‘3’과 자리를 바꾸면 모든 서브트리가 max heap tree의 조건을 만족하는 상태가 된다.

5. “위의 2, 3, 4번 과정을 배열의 크기가 1이 될때 까지 반복한다.”

이제 다시 새로뽑힌 root와 마지막 node인 2를 swap하고 배열 크기를 하나 줄인 다음 새로운 node의 자리를 찾아준다. 즉, node를 swap하고 index를 하나 줄이는 과정을 O(N)번 반복 하고 각 반복 마다 O(log N)의 –정확히는 매 반복 마다 배열의 크기가 하나씩 줄어듬– 비교 연산이 필요하다.  한바퀴 더 돌아 보면.

바꾸고

크기줄이고

자리 찾아주고

이렇게 원소를 하나씩 줄여 가면서 1개가 남을때까지 반복하면 정렬된 배열을 얻게 된다.

Code로 나타내면 다음과 같다. (충분히 시험되지 않았음)

/*
  Name: heapSort
  Desc.: Sorts given array 'arr' as an increasing order.
  Args.:
    - arr : Pointer to array to be sorted.
    - arrSize : Size of the array. (Number of elements in the array)
*/
void heapSort(int* arr, int arrSize)
{
    int arrLastIdx = arrSize - 1;
    buildHeapTree(arr, arrSize);
    while(arrLastIdx > 0)
    {
        swap(arr, 0, arrLastIdx);
        arrLastIdx --;
        maxHeapify(arr, arrLastIdx, 0);
    }
}
/*
  Name: swap
  Desc.: Exchanges two elements of the array 'arr' that two given indices indicates.
  Args.:
    - arr: Pointer to array to be sorted.
    - idx1, idx2 : Two indices to be swapped.
*/
static void swap(int* arr, int idx1, int idx2)
{
    int t = arr[idx1];
    arr[idx1] = arr[idx2];
    arr[idx2] = t;
}

/*
  Name: maxHeapify
  Desc.: Makes given tree and it's sub-trees to be max heap trees.
  Args:
    - arr : Point to array to be sorted.
    - arrayLastIdx : Last index of the given array.
    - parentIdx : Index of the parent node of the tree.
*/
static void maxHeapify(int* arr, int arrayLastIdx, int parentIdx)
{
    int lcIdx = (parentIdx * 2) + 1;  // Index for left child node.
    int rcIdx = lcIdx + 1;            // Index for right child node.
    int biggerChildIdx = lcIdx;       // Index for child that has bigger value.

    // Stop recursion if left child index exceeds last index of the array.
    if(lcIdx > arrayLastIdx)
        return;

    // Left child would be the only on if there's no right child. 
    if(rcIdx > arrayLastIdx)
        biggerChildIdx = lcIdx;
    else   // Which of left/right is bigger if both are exits?
        biggerChildIdx = (arr[lcIdx] < arr[rcIdx]) ? rcIdx : lcIdx;

    // Swap and heapify if child is bigger than parent.
    if(arr[parentIdx] < arr[biggerChildIdx])
    {
        swap(arr, parentIdx, biggerChildIdx);
        maxHeapify(arr, arrayLastIdx, biggerChildIdx);
    }

    return;
}


/*
  Name: buildHeapTree
  Desc.: Makes sure all sub-trees to be max heapified.
  Args.:
    - arr : Pointer to array to be sorted.
    - arrSize : Size of the array.
*/
static void buildHeapTree(int* arr, int arrSize)
{
    int parentIdx = (arrSize / 2) - 1;
    int arrayLastIdx = arrSize - 1;

    for(; parentIdx >= 0; parentIdx--)
    {
        maxHeapify(arr, arrayLastIdx, parentIdx);
    }
}

MinnowboardMAX에 Chromium OS 올려 본 내용 정리

Building Chromium  OS

  • Linux 12.04 LTS
sudo aptitude install git-core gitk git-gui subversion curl

Install depot_tools

Depot_tools를 clone하고 그 경로를 PATH에 추가해 준다.

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"

Download source code

repo init -u https://chromium.googlesource.com/chromiumos/manifest.git
repo sync

Run build

export BOARD=amd64-generic
cd $CHROM_PATH/src/scripts/
cros_sdk -- ./build_packages --board=${BOARD}
cros_sdk -- ./build_image --board=${BOARD}

Flash to USB thumb drive

USB thumb drive를 연결한 상태 (mount 되지 않음)에서 다음 명령어로 flashing한다. 만약 자동으로 mount된 상태라면 umount후에 실행한다.

cros_sdk -- cros flash --board=${BOARD} usb://
SC_chromiumOS_flahsing

Booting up

BIOS에서 Boot Manager ->. EFI Misc Device를 실행하면 Grub화면에 뜨는데 여기에서 ‘Local image A’를 선택하면 Chrome OS가 시작된다.

References & Links

MinnowboardMAX에 Android 올려 본 내용 정리

Android / Chromium OS / Windows를 올려 볼 수 있는 Intel Baytrail 기반의 개발보드인 MinnowboardMAX에 Android 5.1을 install하는 과정을 설명한다.

필요한 것 들

  • Minnowboard MAX판매하는 곳, 2015년 9월 현재 국내에서 판매하는 곳은 없는것 같다.
  • FTDI cable – Serial 출력을 PC에서 받기 위해 guide 문서에는 TTL-232R을 사용하라고  나와 있는데 Amazon.com에서 배송비 빼고 $23정도에 판매한다. 하지만 국내에서도 호환가능한 케이블을 16,500원에 구할 수 있었는데 Windows 10에서 잘 인식되지 않았고 (Windows 7 / Linux에서는 잘 동작함) 핀 배열이 달라서 직접 배선을 연결해 주어야 하는 문제가 있기는 했다. FTDI 항목 참조.
  • HDMI monitor와 cable – 내부 display가 없기 때문에 화면 출력을 위해서는 Micro HDMI 변환 젠더나 이를 지원하는 cable이 있어야 한다.
  • Mouse / Keyboard – USB를 지원하는 mouse와 keyboard가 필요 하다.
  • SD card (16GB 이상) – Android OS가 설치되는 공간이다.
  • USB (thumb) drive – Android OS를 올릴 image를 flashing하기 위해 필요하다 5GB 이상이 필요하다고 하는데, 실제로는 그렇게 image가 큰 것 같진 않다.

Hooking up

minnowboardMAX_connection
(* Image from Minnowboard MAX wiki)

  • Micro-HDMI : HDMI를 지원하는 monitor와 연결
  • Network : Android image file들을 전송해 줄 host와 같은 network에 유선 LAN cable로 연결
  • Power : 구매시에 포함되어 있는 5V adapter에 연결
  • USB thumb drive : Fastboot image를 포함하고 있는 USB drive를 연결
  • USB keyboard : BIOS와 fastboot 진입 후 메뉴 선택등을 위해 keyboard를 연결
  • FTDI Serial : BIOS menu 선택이나 booting log를 보기 위해 필요하나 없어도 동작에는 문제가 없다.

FTDI 연결

“FTDI Serial”의 핀 배열은 다음과 같다.

minnowboardMAX_FTDI
(* Image from Minnowboard MAX wiki)

PN-USBTTL_connector추천되는 TTL-233R cable을 사용한다면 그냥 연결만 해도 되겠지만, 국내에서 판매하는 PN-USBTTL 제품은 GND / VCC / TXD / RXD 만을 지원하는데 이 네개만 연결해도 동작에는 문제가 없다. 다만 한가지 주의 할 점은 일반적인 연결과 달리 MinowboardMAX의 FTDI TXD연결 (4번핀)은 이 케이블의 G-TXD, RXD연결(5번핀)은 W-RXD로 연결해 주어야 한다는 점이다. 일반적으로 RX-TX, TX-RX로 연결하는 것과 다르다.

정리하면 다음과 같다.

FTDI Pin # PN-USBTTL connector
1 (GND) B-GND
3 (VCC) R-VCC
4 (TXD) G-TXD
5 (RXD) W-RXD

마지막으로 serial monitor program (PuTTY나 Minicom 같은)을 열어서 설정을 해주면 serial 입출력을 위한 준비는 끝난다.

Baud rate: 115200
Flow Control: No
Data bits: 8
Stop bits: 1

Firmware update

MinnowboardMAX를 구매 할 때 포함되어 있는 BIOS의 버전은 최신이 아닐 가능성이 많다. Version 0079 이상이면 굳이 업데이트 할 필요는 없으나 필요하다면 다음 과정에 따라 최신 firmware로 업데이트 할 수 있다.

  • Intel firmware resource center에서 MinnowboardMAX용 firmware를 download
  • USB thumb drive를 FAT32로 포맷하고 다운로드 받은 zip file을 풀어서 모든 내용을 복사
  • USB thumb drive를 MinnowboardMAX에 연결하고 전원을 켜기
  • Booting중 F2 혹은 DEL key를 눌러서 BIOS로 진입해서 UEFI shell을 실행
  • UEFI shell에서 다음의 명령어를 입력해서 firmware update를 실행
UEFI shell> fs0:
UEFI fs0:\> MinnowBoard.MAX.FirmwareUpdateX64.efi MinnowBoard.MAX.X64.082.R01.bin

Android image file 구하기

  • Pre-built binary download
    : 빌드 안해도 되는건 좋은데, userdebug image는 su 명령어를 사용할 수 없어서 제약이 있을 수 있다는 점을 고려해야 한다.
wget https://download.01.org/android-ia/releases/android-5.1.0_r1-ia0-minnowboard_max-64bit-userdebug.zip
  • MinnowboardMAX용 Android source code를 download 받고 직접 build
repo init -u https://github.com/android-ia/platform_manifest -b release/android-5.1.0_r1-ia0
repo sync -j4 -q -c --no-clone-bundle
source build/envsetup.sh
lunch minnow_64p-eng
make -j$(nproc) dist

Creating a fastboot USB thumb drive

Android image를 구했다면 fastboot-usb.img file을 USB thumb drive에 write한다. Linux를 사용한다면 USB drive를 unmount한다음 dd utility로 해당 device 경로에 write하고, Windows를 사용한다면 Win32 Disk imager 혹은 그와 비슷한 program을 사용하면 된다.

다음 예제는 Linux host에서 /media/THUMBDRIVE에 mount된 drive를 해제하고 /dev/sdg1 device path에 writing하는 상황을 설명한다. 당연한 말이지만, 자동으로 mount되지 않았다면 umount를 실행 필요가 없고, 연결된 device path에 대한 정보는 dmesg를 통해 확인할 수 있다.

sudo umount /media/THUMBDRIVE
sudo dd bs=1M if=fastboot-usb.img of=/dev/sdg1 conv=fsync

Flashing Android Image files

fastboot-usb.img가 설치된 USB thumb drive를 연결하고 USB drive로 MinnowboardMAX를 부팅시키면 다음과 같은 화면이 나온다. ‘BOOTLOADER ERROR CODE 04’라고 나오긴 하지만 사실 오류는 아니고 사용자입력을 기다리는 화면이다. SD card와 LAN cable이 제대로 연결되었는지 다시 한 번 확인하고 계속 하기위해 연결된 key board의 윗쪽 화살표키를 누른다.

Intel_bootloader_error_code_04

한참동안 화면 업데이트가 없어서 동작하지 않는것 처럼 보일수도 있는데, 연결된 Serial port로는 kernel이 load되고 실행되는 과정이 보이고 있을 것이다. Serial port에서 booting이 완료되는 것이 보이면, MinnowboardMAX와 같은 network에 연결되어 있는 host PC에서 다음 명령어를 수행해서 image file들을 LAN으로 전송한다.

# Linux
$ provision.sh <IP_ADDR>

# Windows
C:> provision.bat <IP_ADDR>

Tips

  • 실제로 잘 먹힌것인지는 모르겠는데… Network이 안 잡혀서 헤매다가 BIOS에서 IPv4 설정하는 menu가 있어서 DHCP를 설정해 주었다. Network을 못 잡는 다거나 한다면 한번 시도해 보자.
    – Device Manager -> Network Device List -> MAC:xx:xx:xx:xx:xx:xx -> IPv4 Network

SC_enabling_DHCP_from_BIOS

  • Guide 문서에 나와 있는것과는 달리 network 설정화면이 나오지 않아서 MinnowboardMAX의 IP 주소가 무엇을 받았는지 몰랐는데, 공유기의 IP 할당 테이블을 보면 유추할 수 있다.

SC_guessing_minnowboard_IP“할당된 device는 4개인데 사용중인 디바이스는 3개니까… IP는 중간에 건너뛴 4가 아니면 6으로 끝나지 않을까?” 너무 막 찍는것 같지만 실제로 4번으로 끝나는 IP였다! 😉

Boot up

이제 USB thumb drive를 빼고, BIOS menu에서 SD card로 부팅하도록 설정하면 Android로 부팅되는 것을 볼 수 있을 것이다.

ADB over network

USB로 직접 연결할 수 없으므로, 같은 network에 연결되어 있는 PC에서 ADB over network으로 ADB를 실행시킬 수 있다. 먼저 serial emulator program으로 Android device에서 다음을 실행 시킨다.

#> adb tcpip 5555

이제 host PC에서 다음 명령어로 연결한다.

CMD> adb connect 192.168.173.4:5555
CMD> adb devices

References & Links