페이지

레이블이 Algorithms인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Algorithms인 게시물을 표시합니다. 모든 게시물 표시

2012년 5월 16일 수요일

Find the least common ancestor of two node in binary tree

Binary Search Tree는 항상 부모 노드의 왼쪽 자식 노드는 부모 노드보다 작은 값을, 오른쪽은 큰 값을 가지도록 설계되어져 있으므로, Binary Search Tree에서 LCA (Least Common Ancestor)는 두 값이 분기하는 노드가 LCA가 된다. 예를 들어 , 노드 4와 7의 LCA는 6이 된다. 노드 6과 4의 LCA는 6이 된다.

Copied from http://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Binary_search_tree.svg/200px-Binary_search_tree.svg.png

하지만, Binary Tree의 경우에는 이런 규칙이 없으므로, LCA를 찾기 위해 좀 더 복잡한 방법이 필요하다.
copied from http://www.cs.cmu.edu/~adamchik/15-121/lectures/Trees/pix/tree1.bmp

예를 들어 Node 1와 2의 LCA는 7이지만, Binary Search Tree에서 이용한 방법을 적용할 수 없다.
따라서, Binary Tree에서 LCA를 찾기 위한 다양한 방법을 인터넷에서 찾을 수 있다.

여기서 구현한 방법은 LinkedList를 이용하여 각 Node의 Path를 저장하고, LinkedList의 내용을 비교하면서 Node가 달라지는 시점을 LCA로 인식하는 방법이다.

예를 들어,  Node 2와 12의 LCA를 구한다고 가정한다. 그러면, Node 12의 Path가 LinkedList에서 8->5->7->12로 저장되고, Node 2의 Path가 8->5->7->12->2로 저장된다.
두 개의 LinkedList의 값을 앞에서 부터 하나씩 비교해 나가면, 12 다음부터 두 Node의 Path가 변경됨을 인식함으로, LCA는 12가 된다.

아래 코드를 재귀 호출을 이용하여 각 Node Path를 찾고, Node Path를 비교하면서 LCA를 찾는 코드이다.

    public static LinkedList findNode( Node root, int val ) {
        // root가 null이면 null을 리턴
        if( root==null )
            return null;
        // root의 값의 찾는 Node 값이면, LinkedList의 앞부분에 추가하고 리턴
        LinkedList list = new LinkedList();
        if( root.getValue()==val ) {
            list.addFirst( root.getValue() );
            return list;
        }
        // root노드의 자식 노드들이 모두 null이면, null을 리턴
        if( root.getLeft()==null && root.getRight()==null )
        return null;

        // root의 왼쪽 Node 검색
        if( root.getLeft()!=null ) {
            list = findNode( root.getLeft(), val );
            // 리턴 값이 null이 아니면 현재 Node 값을 LinkedList 앞에 추가
            if( list!=null ) {
                list.addFirst( root.getValue() );
                return list;
            }
        }
        if( root.getRight()!=null  ) {
            list = findNode( root.getRight(), val );
            if( list!=null ) {
              list.addFirst( root.getValue() );
              return list;
            }
        }
        
        return null;
    }

   

    public static void findLCA( Node root, int p, int q ) {

        // root가 null 인지 확인

        if( root==null )
            System.out.println("Tree is empty");


        // 각 Node의 Path를 저장하기 위한 2개의 LinkedList 생성

        LinkedList pathP = new LinkedList();
        LinkedList pathQ = new LinkedList();

        pathP = findNode( root, p );
        pathQ = findNode( root, q );

        // LinkedList가 Null인지 확인
        if( pathP==null || pathQ==null ) {
        System.out.println( " Can't find LCA" );
        return;
        }
        // iteration을 위한 값 설정
        // 두 개의 LinkedList 중 size가 적은 것을 기준으로 iteration하면서 path 확인 
        int nSize = Math.min( pathP.size(), pathQ.size() );
        int LCA = -32767;
        int pVal = -32767;
        int qVal = -32767;
        int i=0;
       

        while( i

           pVal = pathP.poll();
           qVal = pathQ.poll();
           // Path 값이 동일하면 LCA 값 Update
           if( pVal==qVal )
               LCA = pVal;
           else
               break;
            i++;
        }
        if( LCA==-32767 )
        System.out.println( " Can't find LCA" );
        else
        System.out.println( " LCA is " + LCA );
    }

2012년 5월 15일 화요일

How to check if a tree is balanced

root 노드의 왼쪽 Subtree와 오른쪽 Subtree의 높이의 차이가 1이하인 경우 Tree가 균형잡혀있다고 할 수 있으므로, 각 Subtree의 최대 깊이와 최소 깊이를 구하여 그 차이를 구한다.


/*
 * pseudo code: need more elaboration to run
*/
    public static int maxDepth( Node root ) {
        if( root==null )
            return 1;
        return (1 + Math.max( maxDepth(root.getLeft()), maxDepth(root.getRight()) );
    }

    public static int minDepth( Node root ) {
        if( root==null )
            return 1;
        return (1 + Math.min( minDepth(root.getLeft()), minDepth(root.getRight()) );
    }


    public static boolean isBalanced( Node root ) {
        int nMax = maxDepth( roor );
        int nMin = minDepth( roor );
        if( (nMax-nMin)>1 )
            System.out.println( "Not balanced" );
        else
             System.out.println( "Balanced" );
    }


2012년 5월 14일 월요일

QuickSort

Java를 이용하여 String을 QuickSort하는 루틴...
Javad에서 숫자를 sorting하는 것보다, String을 sorting하는 경우에는 typecasting에 대해 신경을 더 써야한다.


    public static char [] sortString( char [] in, int low, int high ) {
   
    if( low>high )
    return in;
        int pivotPos = low + (high-low)/2;
    char pivot = in[pivotPos];
        int lowCnt = low;
        int highCnt = high;
        /*
         * Pivot 문자를 맨 뒤의 문자와 교환한다.
         * 중복 문자가 입력된 경우를 대비 
         문자 치환을 위해 Exclusive-OR를 이용하고,  그 결과를 Typecasting한다. 
        */
        in[high] = (char)(in[high] ^ in[pivotPos]);
        in[pivotPos] = (char)(in[high] ^ in[pivotPos]);
        in[high] = (char)(in[high] ^ in[pivotPos]);
     
        while( lowCnt

              /*
              * Low index에서부터  1씩 증가하며, Pivot 문자보다 뒷 순서의 문자를 찾는다.
              */

             while( in[lowCnt]
                 lowCnt++;

             while( in[highCnt]>=pivot && lowCnt
                 highCnt--;

              /*
              * High index에서부터  1씩 감소시키며, Pivot 문자보다 앞 순서의 문자를 찾는다.
              */



              /*
              * 찾은 문자를 교환한다.
              */

            if( lowCnt
                in[lowCnt] = (char)(in[lowCnt]  ^ in[highCnt]);
                in[highCnt] = (char)(in[lowCnt]  ^ in[highCnt]);
                in[lowCnt] = (char)(in[lowCnt]  ^ in[highCnt]);
                if( (lowCnt+1)
                lowCnt++;
                if( (highCnt-1)>low )
                highCnt--;
            }
           
        }
        /*
         * PLow Counter의 문자와 맨 뒤 문자를 비교하여, .
          맨 뒤에 나중 순서의 문자를 배치한다.
         * 중복 문자가 입력된 경우를 대비 
        */
        if( in[lowCnt]>in[high]) {
        in[lowCnt] = (char)(in[lowCnt] ^ in[high]);
        in[high] = (char)(in[lowCnt] ^ in[high]);
        in[lowCnt] = (char)(in[lowCnt] ^ in[high]);
        }
       
       if( (lowCnt-1)>low )
           in = sortString( in, low, lowCnt-1 );
       if( (highCnt+1)
           in = sortString( in, highCnt+1, high );
             
       return in;

    }
   
    public static String sortString( String in ) {
        int high = in.length();
        int low = 0;
        char [] out = new char [high];
        /*
         toCharArray()를 이용하여 String을 char array로 복사
         */
        out = in.toCharArray();
       
        out = sortString( out, 0, high-1 );

        /*
         copyValueOf()를 이용하여 char array의 값을 String으로 복사
         */

        return in.copyValueOf(out);
    }

2012년 5월 13일 일요일

Check if a binary tree is a binary search tree

Binary Search Tree는 아래 그림(Wikipedia에서 복사)에서 보는 것과 같이 root node의
왼쪽 Subtree는 root node의 값 8보다 적은 값들만,
오른쪽 Subtree는 root node의 값 8보다 큰 값들만 분포되도록 만들어진 Tree이다.


따라서, 주어진 Tree가 Binary Search Tree인지 아닌지 확인하기 위해서는, root node를 positive/negative infinite number와 비교하여 root node가 positive/negative infinite number 내에 존재하는지를 확인한다. 
만약, positive/negative infinite number 내에 존재하면, root node 의 값을 최대값으로 하여 왼쪽 subtree가 root node 값보다 작은 값으로 구성되어져 있는지 확인힌다.
마친가지로, 오른쪽 Subtree로 root node의 값을 최소값으로하여 오른쪽 Subtree의 값들이 root node 값보다 큰 값으로 구성되어져 있는지 확인한다. 왼쪽 Subtree와 오른쪽 Subtree를 확인한 값이 모두 참인 경우에 Binary Search Tree가 된다.

주의.  논란의 여지는 있지만, null tree인 경우에는 Binary Search Tree로 정의한다.

boolean isBST( node root, int MAX, int MIN ) {
    if( root==null )
        return true;
    if( MAX>root.getValue() && MIN < root.getValue() )
        return( isBST(root.getLeft(), MIN, root.getValue() )  && isBST(root.getRight(),root.getValue(), MAX ) );
    else
        return false;
    }
}

2012년 5월 10일 목요일

Levenshtein Distance

Levenshtein Distance는 한 문자열을 다른 문자열로 바꿀 때 몇 번의 변경이 필요한지를 측정하는 방식이다. 예를 들어, 새끼 고양이를 뜻하는 kitten을 앉아있다는 sitting으로 변경하기 위해서는

kitten → sitten : 첫번째 문자 k를 s로 변경
sitten → sittin  : 끝에서 2번째 문자인 e를 i로 변경
sittin → sitting : 마지막으로 g를 문자열 마지막에 추가

과 같은 과정을 거치게됨으로 Levenshtein Distance는 3이 된다. 

Levenshtein Distance를 구하기 위해서는 2차원 배열를 이용하는데, 첫번째 Row에 문자열 하나를 (여기서는 kitten)을, 첫번째 Column에 다른 문자를 (여기서는 sitting)을 순차적인 숫자로 변환하여 입력한다.

다음 s와 kitten에 대한 거리를 계산한다.
먼저 (s,k)는 같은 문자가 아니므로 (s,k) 셀의 왼쪽, 위, 그리고 왼쪽/위 대각선의 값에 1을 더한 값 중에 최소 값을 입력한다. (s,k) cell의 왼쪽 cell과 위쪽 cell 값은 2, 왼쪽/위 대각선은 1이 됨으로 1을 입력한다.
  (s,i) cell 역시 두 문자가 같지 않으므로, (2,3,2) 중에 최소값인 2가 된다.  동일한 방법으로 나머지 cell의 값을 입력한다.
그런데, (i,i) cell의 경우, 두 문자가 동일하기에 왼쪽/위 대각선 값을 입력한다. 여기서는 1이 된다.
완성된 배열은 다음과 같다.

완성된 배열에서 Levenshtein Distance는 마지막 cell인 (g,n)의 값이 된다. 3....
다음은 Wikipedia에 있는 Levenshtein Distance (http://en.wikipedia.org/wiki/Levenshtein_distance)를 구하는 알고리즘이다.

int LevenshteinDistance(char s[1..m], char t[1..n])
{
    // for all i and j, d[i,j] will hold the Levenshtein distance between
    // the first i characters of s and the first j characters of t;
    // note that d has (m+1)x(n+1) values
    declare int d[0..m, 0..n]

    for i from 0 to m
        d[i, 0] := i // the distance of any first string to an empty second string
    for j from 0 to n
        d[0, j] := j // the distance of any second string to an empty first string

    for j from 1 to n {
        for i from 1 to m {
            if s[i] = t[j] then  
                d[i, j] := d[i-1, j-1]       // no operation required
            else
                d[i, j] := minimum (
                                d[i-1, j] + 1,  // a deletion
                                d[i, j-1] + 1,  // an insertion
                                d[i-1, j-1] + 1 // a substitution
                            )
        }
    }
    return d[m,n]
}

위의 알고리즘에서 보듯이 Levenshtein Distance를 구하기 위한 Time Complexity O(m*n)이 되겠다.