자료 구조2020. 9. 1. 13:13

이진 트리

모든 노드가 최대 2개의 자식을 가질 수 있는 트리이다.

컴파일러나 검색 등에 사용되는 특수 자료구조 (ex : 이진 탐색 트리(Binary Search Tree), 수식 이진 트리(Expression Binary Tree)) 


이진 트리의 형태

포화 이진 트리 (Full Binary Tree): 잎 노드를 제외한 모든 노드들이 2개의 자식을 가지고 있는 트리


완전 이진 트리 (Complete Binary Tree): 잎 노드들이 트리의 왼쪽부터 채워진 트리

아래의 그림은 완전 이진 트리가 아닌 예이다.

높이 균형 트리 (Height Balanced Tree)

루트 노드를 기준으로 왼쪽 하위 트리와 오른쪽 하위 트리의 높이가 1이상 차이가 나지 않는 이진 트리


완전 높이 균형 트리 (Completely Height Balanced Tree)

루트 노드를 기준으로 왼쪽 하위 트리와 오른쪽 하위 트리의 높이가 같은 이진 트리



이진 트리의 순회(Traversal)

트리 내의 노드들 사이를 돌아다니는  것을 말한다.


순회의 종류

전위 순회(Preorder) : 루트 노드부터 잎 노드 까지 아래 방향으로 방문하는 방법


중위 순회(Inorder) : 왼쪽 하위 트리부터 오른쪽 하위 트리 방향으로 방문하는 방법


후위 순회(Postorder) : 루트, 왼쪽 하위 트리, 오른쪽 하위 트리 순으로 방문하는 방법



이진 트리 노드 구조체

typedef char ElementType;


typedef struct tagSBTNode

{

struct tagSBTNode* Left;

struct tagSBTNode* Right;

ElementType Data;

} SBTNode;


이진 트리 노드 소스코드


#include "BinaryTree.h"


SBTNode* SBT_CreateNode( ElementType NewData )

{

    SBTNode* NewNode = (SBTNode*)malloc( sizeof(SBTNode) );

    NewNode->Left    = NULL;

    NewNode->Right   = NULL;

    NewNode->Data    = NewData;


    return NewNode;

}


void SBT_DestroyNode( SBTNode* Node )

{

    free(Node);

}


void SBT_DestroyTree( SBTNode* Node )

{

    if ( Node == NULL )

        return;


    /*  왼쪽 하위 트리 소멸 */

    SBT_DestroyTree( Node->Left );


    /*  오른쪽 하위 트리 소멸 */

    SBT_DestroyTree( Node->Right );


    /*  루트 노드 소멸 */

    SBT_DestroyNode( Node );

}


void SBT_PreorderPrintTree( SBTNode* Node )        //전위 순회를 이용한 이진 트리 출력

{

    if ( Node == NULL )

        return;


    /*  루트 노드 출력 */

    printf( " %c", Node->Data );


    /*  왼쪽 하위 트리 출력 */

    SBT_PreorderPrintTree( Node->Left );


    /*  오른쪽 하위 트리 출력 */

    SBT_PreorderPrintTree( Node->Right );

}


void SBT_InorderPrintTree( SBTNode* Node )        //중위 순회를 이용한 이진 트리 출력

{

    if ( Node == NULL )

        return;

    

    /*  왼쪽 하위 트리 출력 */

    SBT_InorderPrintTree( Node->Left );


    /*  루트 노드 출력 */

    printf( " %c", Node->Data );

    

    /*  오른쪽 하위 트리 출력 */

    SBT_InorderPrintTree( Node->Right );

}


void SBT_PostorderPrintTree( SBTNode* Node )       //후위 순회를 이용한 이진 트리 출력

{

    if ( Node == NULL )

        return;

    

    /*  왼쪽 하위 트리 출력 */

    SBT_PostorderPrintTree( Node->Left );


    /*  오른쪽 하위 트리 출력 */

    SBT_PostorderPrintTree( Node->Right );


    /*  루트 노드 출력 */

    printf( " %c", Node->Data );

}


'자료 구조' 카테고리의 다른 글

수식 트리 (Expression Tree)  (0) 2020.09.01
분리 집합 (Disjoint Set)  (0) 2020.09.01
Tree (트리)  (0) 2012.05.23
Linked Queue(링크드 큐)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Posted by elluma
자료 구조2020. 9. 1. 13:13

수식을 표현하는데 사용되는 이진 트리

수식 트리는 하나의 연산자가 두 개의 피연산자를 가진다고 가정한다.


수식 트리는 다음의 조건을 가진다.

  • 피연산자는 잎 노드이다.
  • 연산자는 루트 노드 또는 가지 노드 이다.


3 * 4 + (8 - 6) 수식을 이진 트리로 표현하게 되면 다음 아래의 그림과 같이 된다.


피연산자(3, 4, 6, 8)는 모두 잎 노드이고, 연산자(+, *, -)는 루트 노드이거나 가지 노드 이다.


수식 트리에서는 왼쪽 하위 트리, 오른쪽 하위 트리를 거쳐 루트 노드 순으로 순회하는 하위 순회를 사용한다.


수식 트리의 구축

일반적으로 사용하는 수식을 표기하는 중위 표기식은 컴퓨터가 처리하기에 적합하지 않으므로 먼저 수식을 후위 표기식으로 변환한다.

(중위 표기식을 후위 표기식으로 변환하는 방법 - http://kbms.tistory.com/10)


'3 * 4 + (8 - 6)' 수식을 후위 표기식으로 바꾸면 '3 4 * 8 6 - +' 이다


수식 트리 구축 알고리즘

  1. 수식의 뒤에서부터 앞으로 읽는다.
  2. 수식의 제일 마지막이 루트 노드이다. (후위 표기식의 마지막은 언제나 연산자)
  3. 수식에서 읽은 토큰이 연산자인 경우 가지 노드가 되고 이 다음 2개의 토큰은 오른쪽 자식과 왼쪽 자식 노드가 된다. (하지만 다음 토큰에서 연산자인 경우에는 이 토큰으로 부터 만들어지는 하위 트리가 완성된 이후에 읽어낸 토큰이 왼쪽 자식 노드이다.)
  4. 수식에서 읽은 토큰이 숫자이면 잎 노드이다.


'3 4 * 8 6 - +' 수식을 트리로 구축하는 과정


3 4 * 8 6 - +

가장 마지막인 '+'연산자가 루트 노드가 된다.

3 4 * 8 6 - +

다음 토큰으로 '-'연산자를 읽어 루트노드의 왼쪽 자식 노드가 된다.

3 4 * 8 6 - +

다음 토큰 두 개는 숫자(피연산자)이므로 각각 '-'노드의 양쪽 자식이 된다.

3 4 * 8 6 - +

다음 토큰으로 '*'(연산자)로 루트 노드인 '+'노드의 왼쪽 자식 노드가 된다.

3 4 * 8 6 - +

나머지 토큰인 숫자(피연산자)는 '*'노드의 양쪽 자식 노드가 된다.

완성된 수식 트리를 확인 할 수 있다.




수식 트리 구현 소스코드


#include "ExpressionTree.h"


ETNode* ET_CreateNode( ElementType NewData )

{

    ETNode* NewNode = (ETNode*)malloc( sizeof(ETNode) );

    NewNode->Left    = NULL;

    NewNode->Right   = NULL;

    NewNode->Data    = NewData;


    return NewNode;

}


void ET_DestroyNode( ETNode* Node )

{

    free(Node);

}


void ET_DestroyTree( ETNode* Root )

{

    if ( Root == NULL )

        return;


    ET_DestroyTree( Root->Left );

    ET_DestroyTree( Root->Right );

    ET_DestroyNode( Root );

}


void ET_PreorderPrintTree( ETNode* Node )

{

    if ( Node == NULL )

        return;


    printf( " %c", Node->Data );


    ET_PreorderPrintTree( Node->Left );

    ET_PreorderPrintTree( Node->Right );

}


void ET_InorderPrintTree( ETNode* Node )

{

    if ( Node == NULL )

        return;

    

    printf( "(" );

    ET_InorderPrintTree( Node->Left );


    printf( "%c", Node->Data );


    ET_InorderPrintTree( Node->Right );

    printf( ")" );

}


void ET_PostorderPrintTree( ETNode* Node )

{

    if ( Node == NULL )

        return;

    

    ET_PostorderPrintTree( Node->Left );

    ET_PostorderPrintTree( Node->Right );

    printf( " %c", Node->Data );

}


void ET_BuildExpressionTree( char* PostfixExpression, ETNode** Node )

{

    ETNode* NewNode = NULL;

    int  len        = strlen( PostfixExpression );

    char Token      = PostfixExpression[ len -1 ];

    PostfixExpression[ len-1 ] = '\0';


    switch ( Token ) 

    {

        /*  연산자인 경우 */

        case '+': case '-': case '*': case '/':

            (*Node) = ET_CreateNode( Token );

            ET_BuildExpressionTree( PostfixExpression, &(*Node)->Right );

            ET_BuildExpressionTree( PostfixExpression, &(*Node)->Left  );

            break;


        /*  피연산자인 경우 */

        default :

            (*Node) = ET_CreateNode( Token);

            break;

    }

}


double ET_Evaluate( ETNode* Tree )

{

    char Temp[2];

    

    double Left   = 0;

    double Right  = 0;

    double Result = 0;


    if ( Tree == NULL )

        return 0;


    switch ( Tree->Data ) 

    {

        /*  연산자인 경우 */

        case '+': case '-': case '*': case '/':

            Left  = ET_Evaluate( Tree->Left );

            Right = ET_Evaluate( Tree->Right );


                 if ( Tree->Data == '+' ) Result = Left + Right;

            else if ( Tree->Data == '-' ) Result = Left - Right;

            else if ( Tree->Data == '*' ) Result = Left * Right;

            else if ( Tree->Data == '/' ) Result = Left / Right;            


            break;


        /*  피연산자인 경우 */

        default :

            memset(Temp, 0, sizeof(Temp));

            Temp[0] = Tree->Data;

            Result = atof(Temp);  

            break;

    }


    return Result;

}


'자료 구조' 카테고리의 다른 글

Binary Tree (이진 트리)  (0) 2020.09.01
분리 집합 (Disjoint Set)  (0) 2020.09.01
Tree (트리)  (0) 2012.05.23
Linked Queue(링크드 큐)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Posted by elluma
자료 구조2020. 9. 1. 13:13

분리 집합이란

서로 공통되는 원소를 가지지 않는 집합을 의미한다.

'교집합'이 존재하지 않는 집합 ('합집합만 존재한다.)

아래의 그림은 분리 집합의 예이다.


위의 분리 집합을 트리로 표현하게 되면 아래의 그림과 같이 나타낼 수 있다.

분리 집합의 트리 구조에서는 부모가 자식을 가리키지 않고 자식이 부모를 가리키는 방식으로 나타낸다.

루트 노드는 집합의 그 자체를 뜻하고 루트 노드 자신을 가리키는 모든 노드들은 그 집합에 속한다.

분리 집합의 연산

분리 집합의 연산에는 '합집합'이 있는데, 두 집합을 더하는 연산을 말한다.

트리 구조에서는 오른쪽 집합의 루트 노드를 왼쪽 집합 루트 노드의 자식 노드로 만들면 된다.


집합 탑색(Find) 연산

집합에서 원소가 속해 있는 집합을 찾는 연산

집합 내의 어떤 노드든 루트 노드가 나타내는 집합이 곤 자신이 속해 있는 집합이므로, 노드가 어떤 집합에 속해 있는지 알려면 이 원소가 속해 있는 트리의 루트 노드를 찾으면 된다.

부모 노드를 가리키는 포인터가 NULL인 노드가 루트 노드이다.


분리 집합 소스코드

#include "DisjointSet.h"


void DS_UnionSet( DisjointSet* Set1, DisjointSet* Set2 )    //합집합 함

{

    Set2 = DS_FindSet(Set2);

    Set2->Parent = Set1;

}


DisjointSet* DS_FindSet( DisjointSet* Set )    //집합 탐색 함수

{

    while ( Set->Parent != NULL )

    {

        Set = Set->Parent;

    }


    return Set;

}


DisjointSet* DS_MakeSet( void* NewData )

{

    DisjointSet* NewNode = (DisjointSet*)malloc(sizeof(DisjointSet));

    NewNode->Data   = NewData;

    NewNode->Parent = NULL;


    return NewNode;

}


void DS_DestroySet( DisjointSet* Set )

{

    free( Set );

}


'자료 구조' 카테고리의 다른 글

Binary Tree (이진 트리)  (0) 2020.09.01
수식 트리 (Expression Tree)  (0) 2020.09.01
Tree (트리)  (0) 2012.05.23
Linked Queue(링크드 큐)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Posted by elluma
자료 구조2012. 5. 23. 16:37

다음 그림과 같은 구조를 가지는 것이 트리(Tree)라 한다.


트리는 Root, Branch, Leaf 요소를 가진다.

Root(뿌리) : 트리 구조에서 가장 위에 있는 노드 (그림 A노드)

Leaf(잎) : 트리 구조에서 가장 끝에 있는 노드 (그림 E, F, H, K 노드)

Branch(가지) : Root와 Leaf 사이에 위치한 노드  (그림 D, G, I, C, D, J 노드)


부모(Parent) 자식(Children) 관계
노드 B, C, D에서  B는 C와 D의 부모이고 C와 D는 B의 자식이다. C와 D는 형제(Sibling)이다.

경로(Path)
A노드에서 E노드로 찾아간다고 가정했을 때, A에서 출발해 B노드 지나 D노드에 도착한 후 E노드를 찾아가게 된다.
여기서 A, B, D, E가 A노드에서 E노드 까지의 경로이다.
경로는 길이(Length) 속성을 가진다. 출발 노드에서 도착 노드까지 거쳐야 하는 노드의 수를 나타낸다.
A, B, D, E 경로의 길이는 3이 된다.

깊이(depth)
Root 노드에서 해당하는 노드까지의 경로의 길이를 말한다.
A노드의 깊이는 0
B,G,I 노드의 깊이는 1
C, D, H, J 노드의 깊이는 2
E, F, K 노드의 깊이는 3

레벨(Level)
깊이가 같은 노드의 집합을 말한다.
레벨 2는 C, D, H, J 이다.

높이(Height)
가장 깊이가 깊은 잎 노드의 깊이를 말한다.
트리의 높이는 3이다.

차수(Degree)
해당 노드의 자식 노드 개수를 말한다.
A노드의 차수는 3, B노드의 차수는 2, G노드의 차수는 1이다.

트리의 노드
typedef char ElementType;

typedef struct tagTreeNode
{
struct tagTreeSNode* LeftChild;    //자식 노드를 가리키는 포인터
struct tagTreeNode* RightSibling;    //형제 노드를 가리키는 포인터

ElementType Data;
} TreeNode;

Tree 소스코드


#include "Tree.h"


TreeNode* Tree_CreateNode( ElementType NewData )

{

    TreeNode* NewNode = (TreeNode*)malloc( sizeof(TreeNode) );

    NewNode->LeftChild    = NULL;

    NewNode->RightSibling = NULL;

    NewNode->Data = NewData;


    return NewNode;

}


void Tree_DestroyNode( TreeNode* Node )

{

    free(Node);

}


void Tree_DestroyTree( TreeNode* Root )

{

    if ( Root->RightSibling != NULL )

        Tree_DestroyTree( Root->RightSibling );


    if ( Root->LeftChild != NULL )

        Tree_DestroyTree( Root->LeftChild );


    Root->LeftChild = NULL;

    Root->RightSibling = NULL;


    Tree_DestroyNode( Root );

}


void Tree_AddChildNode( TreeNode* Parent, TreeNode *Child)

{

    if ( Parent->LeftChild == NULL )

    {

        Parent->LeftChild = Child;

    }

    else 

    {

        TreeNode* TempNode = Parent->LeftChild;

        while ( TempNode->RightSibling != NULL )

            TempNode = TempNode->RightSibling;


        TempNode->RightSibling = Child;        

    }

}


void Tree_PrintTree( TreeNode* Node, int Depth )

{

    int i=0; 

    for ( i=0; i<Depth; i++ )    //깊이만큼 공백 출력

        printf(" ");


    printf("%c\n", Node->Data);    //노드의 데이터 출력


    if ( Node->LeftChild != NULL )

        Tree_PrintTree(Node->LeftChild, Depth+1);


    if ( Node->RightSibling != NULL )

        Tree_PrintTree(Node->RightSibling, Depth);

}


'자료 구조' 카테고리의 다른 글

수식 트리 (Expression Tree)  (0) 2020.09.01
분리 집합 (Disjoint Set)  (0) 2020.09.01
Linked Queue(링크드 큐)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack : 사칙 연산 계산기  (0) 2012.05.14
Posted by elluma
자료 구조2012. 5. 23. 11:25

연결리스트와 같이 링크드 큐의 각 노드는 다음 노드를 가리키는 포인터를 가진다.

순환 큐에 비해서 구현이 쉽고 용량의 제한이 없다. 하지만 순환 큐에 비해서 성능이 떨어진다.(malloc() 함수를 사용하기 때문)


링크드 큐의 노드와 구조체

typedef struct tagNode

{

char* Data;

struct tagNode* NextNode;

} Node;


typedef struct tagLinkedQueue

{

Node* Front;

Node* Rear;

int Count;

} LinkedQueue;


LinkedQueue 소스코드


#include "LinkedQueue.h"


void  LQ_CreateQueue( LinkedQueue** Queue )

{

    /*  큐를 자유저장소에 생성 */

    (*Queue )        = ( LinkedQueue*)malloc(sizeof( LinkedQueue ) );

    (*Queue )->Front = NULL;

    (*Queue )->Rear  = NULL;

    (*Queue )->Count = 0;

}


void LQ_DestroyQueue( LinkedQueue* Queue )

{

    while ( !LQ_IsEmpty( Queue ) )

    {

        Node* Popped = LQ_Dequeue( Queue );

        LQ_DestroyNode(Popped);    

    }


    /*  큐를 자유 저장소에서 해제 */

    free( Queue );

}


Node* LQ_CreateNode( char* NewData )

{

    Node* NewNode = (Node*)malloc( sizeof( Node ) );

    NewNode->Data = (char*)malloc( strlen( NewData) + 1);


    strcpy(NewNode->Data, NewData);  /*  데이터를 저장한다. */


    NewNode->NextNode = NULL; /*  다음 노드에 대한 포인터는 NULL로 초기화 한다. */


    return NewNode;/*  노드의 주소를 반환한다. */

}


void  LQ_DestroyNode(Node* _Node )

{

    free(_Node->Data);

    free(_Node );

}


void LQ_Enqueue( LinkedQueue* Queue, Node* NewNode )

{

    if ( Queue->Front == NULL ) 

    {        

        Queue->Front = NewNode;

        Queue->Rear  = NewNode;

        Queue->Count++;

    } 

    else

    {

        Queue->Rear->NextNode = NewNode;

        Queue->Rear = NewNode;

        Queue->Count++;

    }

}


Node* LQ_Dequeue( LinkedQueue* Queue )

{

    /*  LQ_Dequeue() 함수가 반환할 최상위 노드 */

    Node* Front = Queue->Front;


    if ( Queue->Front->NextNode == NULL )

    {

        Queue->Front = NULL;

        Queue->Rear  = NULL;

    }

    else

    {

        Queue->Front = Queue->Front->NextNode;

    }


    Queue->Count--;


    return Front;

}


int LQ_IsEmpty( LinkedQueue* Queue )

{

    return ( Queue->Front == NULL);

}




'자료 구조' 카테고리의 다른 글

분리 집합 (Disjoint Set)  (0) 2020.09.01
Tree (트리)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack : 사칙 연산 계산기  (0) 2012.05.14
Stack (스택)  (0) 2012.05.11
Posted by elluma
자료 구조2012. 5. 17. 11:51

먼저 들어가고 먼저나오는 '선입선출' 자료구조 (FIFO : First In First Out)


큐의 주요 기능

  • 삽입 (Enqueue)
  • 제거 (Dequeue)
큐의 가장 앞 요소를 전단(Front), 가장 마지막 요소를 후단(Rear) 라고 한다.
큐의 삽입은 후단, 제거는 전단에서 수행된다.


순환 큐 (Circular Queue)

일반적인 배열을 사용하여 큐를 구현하였을때 생기는 "요소를 이동시키는데 발생하는 비용문제, 가용 용량 감소문제"가 발생한다.

이를 해결하기 위해서 큐의 시작과 끝을 연결하여 순환하도록 하는 것이 '순환 큐'이다.


배열의 처음과 끝이 연결되어 원을 이룬다는 가정하에

전단과 후단을 가리키는 변수를 사용, 삽인과 삭제 연산이 수행 될 때마다 전단과 후단의 위치를 변경해주는 방식

※ 배열의 크기는 큐의 크기보다 '1'크게 만들어서 사용한다 (배열의 크기와 큐의 크기가 같을 경우 empty상태와 full상태를 구분하지 못한다.)


큐의 노드 구조체

typedef int ElementType;


typedef struct tagNode

{

ElementType Data;

} Node;


순환 큐의 구조체

typedef struct tagCircularQueue

{

int Capacity;    //용량

int Front;        //전단의 위치

int Rear;        //후단의 위치

Node* Nodes;    //노드 배열

} CircularQueue;

전단과 후단의 위치를 가지는 변수 Front, Rear는 배열 내의 인덱스 값을 가진다.


CircularQueue 소스코드





'자료 구조' 카테고리의 다른 글

Tree (트리)  (0) 2012.05.23
Linked Queue(링크드 큐)  (0) 2012.05.23
Stack : 사칙 연산 계산기  (0) 2012.05.14
Stack (스택)  (0) 2012.05.11
Circular Linked List (환형 연결 리스트)  (0) 2012.05.11
Posted by elluma
자료 구조2012. 5. 14. 19:46

중위 표기법과 후위 표기법

일반적으로 사용하는 수식의 표기법을 '중위 표기법'이라고 한다.

8 - 3 * 2


'후위 표기법'은 연산자를 피연산자 뒤에 위치시킨다는 규칙을 가지고 있다.

아래의 식은 위의 중위 표기법의 수식을 후위 표기법으로 바꾼 것이다.

8 3 2 * -


후위 표기식은 스택을 이용해서 계산할 수 있다.


수식을 읽어 피연산자일 경우 스택에 저장. '8'을 스택에 저장합니다.


'3' 또한 피연산자로 스택에 저장합니다.


'2'도 마찬가지로 스택에 저장합니다.


'*' 연산자가 나타났습니다. 연산자가 나올 경우에는 스택에 저장된 피연산자 2개를 꺼내서 연산자에 해당하는 연산을 하여 결과값을 스택에 저장합니다. 이 과정에서는 '2 * 3'의 연산 결과인 '6'이 스택에 저장됩니다.

마지막으로 '-' 연산자가 나타나 스택에 저장된 피연산자 2개를 꺼내서 연산을 합니다. '8 - 6'의 결과인 '2'가 스택에 저장됩니다.


아래는 이 과정을 순서도로 나타낸 것이다.




중위 표기법에서 후위 표기법으로의 변환 알고리즘

(*중위 표기법의 괄호 : 우선순위가 낮은 연산도 괄호 안에 묶이게 되면 다른 연산보다 우선하여 계산한다. )

  1. 입력받은 중위 표기식에서 토큰을 읽는다.
  2. 토큰이 피연사자이면 토큰을 결과에 출력한다.
  3. 토큰이 연산자(괄호 포함)일 경우, 스택의 최상위 노드의 연산자와 비교하여 우선순위가 높으면(왼쪽 괄호는 우선순위가 가장 낮지만 예외적으로 항상 스택에 삽입) 스택에 삽입하고, 낮을 경우 결과에 출력한다.
  4. 토큰이 ')'이면 최상위 노드에 '('가 올때 까지 스택에 제거 연산을 수행하고 제거한 노드에 담긴 연산자를 출력
  5. 중위 표기식에 더 읽을 것이 없다면 빠져나가고, 읽을 것이 있다면 1부터 다시 반복

 토큰

작업 

출력 

스택 

 (11 + 2) * 15

 스택에 '(' 삽입

 

 ( 

 (11 + 2) * 15  

 11 출력

 11 

 ( 

 (11 + 2) * 15  

 스택에 '+' 삽입

 11

 + ( 

 (11 + 2) * 15  

 2 출력

 11 2  + (
 (11 + 2) * 15  

 스택의 모든 연산자 제거&출력

 11 2 +

 
 (11 + 2) * 15  

 스택에 '*' 삽입

 11 2 + 

 * 

 (11 + 2) * 15  

 15 출력

 11 2 + 15

 * 

 (11 + 2) * 15  

 스택의 모든 연산자 제거& 출력 

 11 2 + 15 * 

 


사칙연산 계산기 소스코드 







'자료 구조' 카테고리의 다른 글

Linked Queue(링크드 큐)  (0) 2012.05.23
Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack (스택)  (0) 2012.05.11
Circular Linked List (환형 연결 리스트)  (0) 2012.05.11
Doubly Linked List (이중 연결 리스트)  (0) 2012.05.11
Posted by elluma
자료 구조2012. 5. 11. 21:14

스택 주차장 

"가장 먼저 들어간 차가 가장 마지막에 나오는 구조"


FILO(First In, Last Out) or LIFO(Last In, First Out)

요소의 삽입과 삭제가 자료구조의 한쪽 끝에서만 이루어지는 특징을 가진다.


스택은 소프트웨어 분야의 중요한 곳에 많이 사용된다.

자동메모리가 스택을 기반으로 동작하고, 거의 대부분의 네트워크 프로토콜도 스택을 기반하고 있다.


스택의 주요 기능

  • 삽입(Push)
  • 제거(Pop)



배열로 구현한 스택

배열을 이용한 스택은 용량을 조절하기 어렵다는 단점이 있지만, 구현이 간단하다는 장점이 있다.


노드 구조체

typedef int ElementType;


typedef struct tagNode

{

ElementType Data;

}Node;


스택 구조체
typedef struct tagArrayStack
{
int Capacity;    //용량
int Top            //최상위 노드의 위치
Node* Nodes; //노드 배열
}ArrayStack;
Nodes 포인터는 자유저장소에 할당한 배열의 첫 번재 요소를 가리킨다.

Array Stack 소스코드





연결 리스트로 구현한 스택


스택의 용량에 제한이 없다.


노드 구조체

typedef struct tagNode

{

char* Data;

struct tagNode* NextNode;

} Node;

문자열을 처리하는 스택

(char* 형은 포인터이기 때문에 문자열이 저당되어 있는 주소만을 담을 수 있고문자열은 자동메모리가 아닌 자유 저장소에 저장되어야 한다.)


스택 구조체

typedef struct tagLinkedListStack

{

Node* List;

Node* Top;

} LinkedListStack;

List 포인터는 연결 리스트의 헤드를 가리키고, Top 포인터는 연결 리스트의 테일을 가리키게 한다.

Top 포인터를 이용하면 4바이트를 소비하고 연결리스트의 테일을 찾는데 소모되는 시간 비용을 제거할 수 있다.


LinkedListStack 소스코드






Posted by elluma
자료 구조2012. 5. 11. 19:30

테일의 다음 노드 포인터가 헤드를 가리키는 형태의 연결리스트


"시작을 알면 끝을 알고, 끝을 알면 시작을 알 수 있다"

테일에서 헤드, 헤드에서 테일로 가는 비용이 거의 없어진다.


테일은 헤드의 '앞 노드'이다.

헤드는 테일의 '뒷 노드'이다.


소스코드







'자료 구조' 카테고리의 다른 글

Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack : 사칙 연산 계산기  (0) 2012.05.14
Stack (스택)  (0) 2012.05.11
Doubly Linked List (이중 연결 리스트)  (0) 2012.05.11
Linked List (연결 리스트)  (0) 2012.05.11
Posted by elluma
자료 구조2012. 5. 11. 18:31

양방향 탐색이 가능한 연결 리스트


typedef struct tagNode

{

int Data

struct tagNode* PrevNode;    //연결리스트 노드 구조체에 이전노드를 가리키는 포인터를 추가

struct tagNode* NextNode;

}Node;


소스코드



'자료 구조' 카테고리의 다른 글

Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack : 사칙 연산 계산기  (0) 2012.05.14
Stack (스택)  (0) 2012.05.11
Circular Linked List (환형 연결 리스트)  (0) 2012.05.11
Linked List (연결 리스트)  (0) 2012.05.11
Posted by elluma
자료 구조2012. 5. 11. 17:03

링크드 리스트는 리스트 구현 기법 중 가장 간단한 방법으로 꼽히는 자료구조


리스트 내의 각 요소는 '노드' (우리말로 '마디'라는 뜻)


링크드 리스트는 '노드를 연결해서 만드는 리스트'




링크드 리스트의 노드

typedef struct tagNode

{

int  Data;                            //데이터 필드

struct tagNode* NextNode;    //다음 노드를 가리키는 포인터

} Node;


Node MyNode;


링크드 리스트의 주요연산

  • 노드 생성/소멸
  • 노드 추가
  • 노드 탐색
  • 노드 삭제
  • 노드 삽입


C언어로 작성된 프로그램의 세가지 메모리영역

정적메모리 (Static Memory) : 프로그램 실행시 프로그램에 사용될 전역변수/정적변수를 메모리에 할당한 후 프로그램 종료시 해제하는 영역

자동메모리 (Automatic Memory) : 스택구조. 코드 블록에서 선언된 변수를 선언 당시에 메모리에 저장했다가 코드 블록 끝에서 자동으로 모두 제거

자유저장소 (Free Store) : 프로그래머가 직접 메모리를 관리하는 메모리 영역


자유저장소에 메모리를 할당려면 malloc() 함수가 필요하다.

void* malloc (size_t size);    //size_t 는 unsigned int의 별칭으로 선언되어 있다.


Node* NewNode = (Node *)malloc(sizeof(Node));


생성한 노드를 소멸은 free() 함수를 사용한다.

void free (void *memblock);


free(NewNode);




소스코드





링크드 리스트의 단점

  • 각 노드마다 다음 노드를 가리키는 포인터로 인한 4byte의 메모리가 추가적으로 필요
  • 노드 탐색을 하는데 비용이 크고 속도가 느리다.


링크드 리스트의 장점

  • 노드의 추가/삽입/삭제가 쉽고 빠르다. (배열과 비교하여)

"링크드 리스트는 레코드를 순차적으로 다루는데 적합하다."






'자료 구조' 카테고리의 다른 글

Queue(큐) : 순환 큐(Circular Queue)  (0) 2012.05.17
Stack : 사칙 연산 계산기  (0) 2012.05.14
Stack (스택)  (0) 2012.05.11
Circular Linked List (환형 연결 리스트)  (0) 2012.05.11
Doubly Linked List (이중 연결 리스트)  (0) 2012.05.11
Posted by elluma